java多线程基本概述(三)——同步块
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-0 end task begin task 长时间处理任务后从远程返回的值1 threadName=Thread-1 长时间处理任务后从远程返回的值2 threadName=Thread-1 end 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-0 end task begin task 长时间处理任务后从远程返回的值1 threadName=Thread-1 长时间处理任务后从远程返回的值2 threadName=Thread-1 end 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 task begin task 长时间处理任务后从远程返回的值1 threadName=Thread-0 长时间处理任务后从远程返回的值2 threadName=Thread-0 end task 长时间处理任务后从远程返回的值1 threadName=Thread-1 长时间处理任务后从远程返回的值2 threadName=Thread-1 end 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=1 nosynchronized threadName=Thread-1 i=1 nosynchronized threadName=Thread-0 i=2 nosynchronized threadName=Thread-1 i=2 nosynchronized threadName=Thread-0 i=3 nosynchronized threadName=Thread-1 i=3 nosynchronized threadName=Thread-0 i=4 nosynchronized threadName=Thread-1 i=4 nosynchronized threadName=Thread-0 i=5 nosynchronized threadName=Thread-1 i=5 nosynchronized threadName=Thread-0 i=6 nosynchronized threadName=Thread-1 i=6 nosynchronized threadName=Thread-0 i=7 nosynchronized threadName=Thread-1 i=7 nosynchronized threadName=Thread-0 i=8 nosynchronized threadName=Thread-1 i=8 =================================同步块同步执行 synchronized threadName=Thread-1 i=85 synchronized threadName=Thread-1 i=86 synchronized threadName=Thread-1 i=87 synchronized threadName=Thread-1 i=88 synchronized threadName=Thread-1 i=89 synchronized threadName=Thread-1 i=90 synchronized threadName=Thread-1 i=91 synchronized threadName=Thread-1 i=92 synchronized threadName=Thread-1 i=93 synchronized threadName=Thread-1 i=94 synchronized threadName=Thread-1 i=95 synchronized threadName=Thread-1 i=96 synchronized threadName=Thread-1 i=97 synchronized threadName=Thread-1 i=98 synchronized threadName=Thread-1 i=99 synchronized threadName=Thread-1 i=100 synchronized threadName=Thread-0 i=1 synchronized threadName=Thread-0 i=2 synchronized threadName=Thread-0 i=3 synchronized threadName=Thread-0 i=4 synchronized threadName=Thread-0 i=5 synchronized threadName=Thread-0 i=6 synchronized threadName=Thread-0 i=7 synchronized threadName=Thread-0 i=8 synchronized threadName=Thread-0 i=9 synchronized threadName=Thread-0 i=10 synchronized threadName=Thread-0 i=11 synchronized threadName=Thread-0 i=12 synchronized threadName=Thread-0 i=13 synchronized threadName=Thread-0 i=14 synchronized threadName=Thread-0 i=15 synchronized threadName=Thread-0 i=16