1.1、synchronized方法的弊端
package commonutils;public class CommonUtils { public static long beginTime1; public static long endTime1; public static long beginTime2; public static long endTime2;}=============================package mytask;import commonutils.CommonUtils;public class Task { private String getData1; private String getData2; public synchronized void doLongTimeTask() { try { System.out.println("begin task"); Thread.sleep(3000); getData1 = "长时间处理任务后从远程返回的值1 threadName=" + Thread.currentThread().getName(); getData2 = "长时间处理任务后从远程返回的值2 threadName=" + Thread.currentThread().getName(); System.out.println(getData1); System.out.println(getData2); System.out.println("end task"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}=======================================package mythread;import commonutils.CommonUtils;import mytask.Task;public class MyThread1 extends Thread { private Task task; public MyThread1(Task task) { super(); this.task = task; } @Override public void run() { super.run(); CommonUtils.beginTime1 = System.currentTimeMillis(); task.doLongTimeTask(); CommonUtils.endTime1 = System.currentTimeMillis(); }}=============================================package mythread;import commonutils.CommonUtils;import mytask.Task;public class MyThread2 extends Thread { private Task task; public MyThread2(Task task) { super(); this.task = task; } @Override public void run() { super.run(); CommonUtils.beginTime2 = System.currentTimeMillis(); task.doLongTimeTask(); CommonUtils.endTime2 = System.currentTimeMillis(); }}
package test;import mytask.Task;import mythread.MyThread1;import mythread.MyThread2;import commonutils.CommonUtils;public class Run { public static void main(String[] args) { Task task = new Task(); MyThread1 thread1 = new MyThread1(task); thread1.start(); MyThread2 thread2 = new MyThread2(task); thread2.start(); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } long beginTime = CommonUtils.beginTime1; if (CommonUtils.beginTime2 < CommonUtils.beginTime1) { beginTime = CommonUtils.beginTime2; } long endTime = CommonUtils.endTime1; if (CommonUtils.endTime2 > CommonUtils.endTime1) { endTime = CommonUtils.endTime2; } System.out.println("耗时:" + ((endTime - beginTime) / 1000)); }}
输出结果:
begin task长时间处理任务后从远程返回的值1 threadName=Thread-0长时间处理任务后从远程返回的值2 threadName=Thread-0end taskbegin task长时间处理任务后从远程返回的值1 threadName=Thread-1长时间处理任务后从远程返回的值2 threadName=Thread-1end task耗时:6
当把同步方法改为同步代码块时,
package mytask;import commonutils.CommonUtils;public class Task { private String getData1; private String getData2; public void doLongTimeTask() { synchronized(Task.class){ try { System.out.println("begin task"); Thread.sleep(3000); getData1 = "长时间处理任务后从远程返回的值1 threadName=" + Thread.currentThread().getName(); getData2 = "长时间处理任务后从远程返回的值2 threadName=" + Thread.currentThread().getName(); System.out.println(getData1); System.out.println(getData2); System.out.println("end task"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }}
输出结果:
begin task长时间处理任务后从远程返回的值1 threadName=Thread-0长时间处理任务后从远程返回的值2 threadName=Thread-0end taskbegin task长时间处理任务后从远程返回的值1 threadName=Thread-1长时间处理任务后从远程返回的值2 threadName=Thread-1end task耗时:6
可见,并没有提升效率,这是因为锁定的范围比较广,所以效果和锁方法的差别并不是太。那么可以缩小边界区,也就是资源真正开始竞争的地方。因为类中的成员变量才是资源的竞争对象,所以需要在访问这些变量的地方进行锁定。那么代码改为如下:
package mytask;import commonutils.CommonUtils;public class Task { private String getData1; private String getData2; public void doLongTimeTask() { try { System.out.println("begin task"); Thread.sleep(3000); getData1 = "长时间处理任务后从远程返回的值1 threadName=" + Thread.currentThread().getName(); getData2 = "长时间处理任务后从远程返回的值2 threadName=" + Thread.currentThread().getName(); synchronized(Task.class){ System.out.println(getData1); System.out.println(getData2); } System.out.println("end task"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
输出结果:
begin taskbegin task长时间处理任务后从远程返回的值1 threadName=Thread-0长时间处理任务后从远程返回的值2 threadName=Thread-0end task长时间处理任务后从远程返回的值1 threadName=Thread-1长时间处理任务后从远程返回的值2 threadName=Thread-1end task耗时:3
这时候可以看到时间已经减小了,这就出现一部分同步,一部分异步了。如何验证是真的一半同步一半异步呢?
package mytask;public class Task { public void doLongTimeTask() { for (int i = 0; i < 100; i++) { System.out.println("nosynchronized threadName=" + Thread.currentThread().getName() + " i=" + (i + 1)); } System.out.println(""); synchronized (this) { for (int i = 0; i < 100; i++) { System.out.println("synchronized threadName=" + Thread.currentThread().getName() + " i=" + (i + 1)); } } }}
输出结果:
=================================非同步块异步执行nosynchronized threadName=Thread-0 i=1nosynchronized threadName=Thread-1 i=1nosynchronized threadName=Thread-0 i=2nosynchronized threadName=Thread-1 i=2nosynchronized threadName=Thread-0 i=3nosynchronized threadName=Thread-1 i=3nosynchronized threadName=Thread-0 i=4nosynchronized threadName=Thread-1 i=4nosynchronized threadName=Thread-0 i=5nosynchronized threadName=Thread-1 i=5nosynchronized threadName=Thread-0 i=6nosynchronized threadName=Thread-1 i=6nosynchronized threadName=Thread-0 i=7nosynchronized threadName=Thread-1 i=7nosynchronized threadName=Thread-0 i=8nosynchronized threadName=Thread-1 i=8=================================同步块同步执行synchronized threadName=Thread-1 i=85synchronized threadName=Thread-1 i=86synchronized threadName=Thread-1 i=87synchronized threadName=Thread-1 i=88synchronized threadName=Thread-1 i=89synchronized threadName=Thread-1 i=90synchronized threadName=Thread-1 i=91synchronized threadName=Thread-1 i=92synchronized threadName=Thread-1 i=93synchronized threadName=Thread-1 i=94synchronized threadName=Thread-1 i=95synchronized threadName=Thread-1 i=96synchronized threadName=Thread-1 i=97synchronized threadName=Thread-1 i=98synchronized threadName=Thread-1 i=99synchronized threadName=Thread-1 i=100synchronized threadName=Thread-0 i=1synchronized threadName=Thread-0 i=2synchronized threadName=Thread-0 i=3synchronized threadName=Thread-0 i=4synchronized threadName=Thread-0 i=5synchronized threadName=Thread-0 i=6synchronized threadName=Thread-0 i=7synchronized threadName=Thread-0 i=8synchronized threadName=Thread-0 i=9synchronized threadName=Thread-0 i=10synchronized threadName=Thread-0 i=11synchronized threadName=Thread-0 i=12synchronized threadName=Thread-0 i=13synchronized threadName=Thread-0 i=14synchronized threadName=Thread-0 i=15synchronized threadName=Thread-0 i=16