首先通過示例來學習驗證多個線程調用同一個方法時隨機的。
package syn_out_asyn; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2017/1/19 0019. */ public class MyList { private List list = new ArrayList(); synchronized public void add(String username){ System.out.println("ThreadName="+Thread.currentThread().getName()+"執行了add方法"); list.add(username); System.out.println("ThreadName="+Thread.currentThread().getName()+"退出了add方法"); } synchronized public int getSize(){ System.out.println("ThreadName= "+Thread.currentThread().getName()+"執行了getSize方法"); int sizeValue= list.size(); System.out.println("ThreadName= "+Thread.currentThread().getName()+"退出了getSize方法"); return sizeValue; } }
package syn_out_asyn; /** * Created by Administrator on 2017/1/19 0019. */ public class ThreadA extends Thread { private MyList list; public ThreadA (MyList list){ super(); this.list = list; } public void run(){ for(int i=0;i<10000;i++){ list.add("ThreadA"+(i+1)); } } }
package syn_out_asyn; /** * Created by Administrator on 2017/1/19 0019. */ public class ThreadB extends Thread { private MyList list; public ThreadB(MyList list){ super(); this.list = list; } public void run(){ for(int i=0;i<10000;i++){ list.add("threadB"+(i+1)); } } }
package syn_out_asyn; /** * Created by Administrator on 2017/1/19 0019. */ public class Run { public static void main(String[] args){ MyList myList = new MyList(); ThreadA threadA = new ThreadA(myList); threadA.setName("A"); threadA.start(); ThreadB threadB = new ThreadB(myList); threadB.setName("B"); threadB.start(); } }
執行結果: ThreadName=A執行了add方法 ThreadName=A退出了add方法 ThreadName=A執行了add方法 ThreadName=A退出了add方法 ThreadName=A執行了add方法 ThreadName=A退出了add方法 ThreadName=B執行了add方法 ThreadName=B退出了add方法 ThreadName=B執行了add方法 ThreadName=B退出了add方法 ThreadName=B執行了add方法 ThreadName=B退出了add方法
從結果來看,同步塊中的代碼是同步打印的,當前線程的執行和退出時成對出現的。但線程A和線程B的執行卻是異步的,這就有可能出現臟讀的環境。由於線程執行的方法的順序不確定,所以當A和B兩個線程執行帶有分之判斷的方法時,就會出現邏輯上的錯誤,有可能出現臟讀。
package t9; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2017/1/20 0020. */ public class MyOneList { private List list = new ArrayList(); synchronized public void add(String data){ list.add(data); } synchronized public int getSize(){ return list.size(); } }
package t9; /** * Created by Administrator on 2017/1/20 0020. */ public class MyService { public MyOneList addServiceMethod(MyOneList list ,String data) { try { if (list.getSize() < 1) { Thread.sleep(2000);//模擬從遠程話費2秒取回數據 list.add(data); } } catch (InterruptedException e) { e.printStackTrace(); } return list; } }
package t9; /** * Created by Administrator on 2017/1/20 0020. */ public class MyThread1 extends Thread { private MyOneList list; public MyThread1(MyOneList list){ super(); this.list=list; } public void run(){ MyService myService = new MyService(); myService.addServiceMethod(list,"A"); } }
package t9; /** * Created by Administrator on 2017/1/20 0020. */ public class MyThread2 extends Thread { private MyOneList list; public MyThread2(MyOneList list){ super(); this.list=list; } public void run(){ MyService myService = new MyService(); myService.addServiceMethod(list,"B"); } }
package t9; /** * Created by Administrator on 2017/1/20 0020. */ public class Run { public static void main(String [] args) throws InterruptedException { MyOneList list = new MyOneList(); MyThread1 thread1 = new MyThread1(list); thread1.setName("A"); thread1.start(); MyThread2 thread2 = new MyThread2(list); thread2.setName("B"); thread2.start(); Thread.sleep(6000); System.out.println("listSize="+list.getSize()); } }
運行結果:
listSize=2
臟讀出現了,原因是兩個線程以異步的方式返回list參數的size()大小,解決的辦法就是同步化。
修改MyService.java
package t9; /** * Created by Administrator on 2017/1/20 0020. */ public class MyService { public MyOneList addServiceMethod(MyOneList list ,String data) { try { synchronized (list) { if (list.getSize() < 1) { Thread.sleep(2000);//模擬從遠程話費2秒取回數據 list.add(data); } } } catch (InterruptedException e) { e.printStackTrace(); } return list; } }
運行結果:
listSize=1
由於list參數對象在項目中是一份實例,是單例的,而且也正需要對list參數的getSize()方法做同步的調用,所以就對list參數進行同步處理。
結論:synchronized(非this對象x):格式的寫法是將x對象本身作為“對象監視器”