首先通过示例来学习验证多个线程调用同一个方法时随机的。
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对象本身作为“对象监视器”