用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法之行一个长时间的任务,那么B线程必须等待比较长的时间,在这样的情况下可以使用synchronized同步语句快来解决。
一、用同步代码块解决同步方法的弊端
Task类
1 package com.weishiyao.learn.day4.testSynchorized.ep2; 2 3 public class Task { 4 5 private String getData1; 6 private String getData2; 7 8 public void doLongTimeTask() { 9 try { 10 System.out.println("begin task"); 11 Thread.sleep(3000); 12 13 String privateGetData1 = "长时间处理任务后从远程返回的值1 threadName=" 14 + Thread.currentThread().getName(); 15 String privateGetData2 = "长时间处理任务后从远程返回的值2 threadName=" 16 + Thread.currentThread().getName(); 17 18 synchronized (this) { 19 getData1 = privateGetData1; 20 getData2 = privateGetData2; 21 } 22 23 System.out.println(getData1); 24 System.out.println(getData2); 25 System.out.println("end task"); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 } 29 } 30 }
常量工具类
1 package com.weishiyao.learn.day4.testSynchorized.ep2; 2 3 public class CommonUtils { 4 5 public static long beginTime1; 6 public static long endTime1; 7 8 public static long beginTime2; 9 public static long endTime2; 10 }
线程类——2个
1 package com.weishiyao.learn.day4.testSynchorized.ep2; 2 3 public class MyThread1 extends Thread { 4 5 private Task task; 6 7 public MyThread1(Task task) { 8 super(); 9 this.task = task; 10 } 11 12 @Override 13 public void run() { 14 super.run(); 15 CommonUtils.beginTime1 = System.currentTimeMillis(); 16 task.doLongTimeTask(); 17 CommonUtils.endTime1 = System.currentTimeMillis(); 18 } 19 20 }
1 package com.weishiyao.learn.day4.testSynchorized.ep2; 2 3 public class MyThread2 extends Thread { 4 5 private Task task; 6 7 public MyThread2(Task task) { 8 super(); 9 this.task = task; 10 } 11 12 @Override 13 public void run() { 14 super.run(); 15 CommonUtils.beginTime2 = System.currentTimeMillis(); 16 task.doLongTimeTask(); 17 CommonUtils.endTime2 = System.currentTimeMillis(); 18 } 19 20 }
运行类
1 package com.weishiyao.learn.day4.testSynchorized.ep2; 2 3 public class Run { 4 5 public static void main(String[] args) { 6 Task task = new Task(); 7 8 MyThread1 thread1 = new MyThread1(task); 9 thread1.start(); 10 11 MyThread2 thread2 = new MyThread2(task); 12 thread2.start(); 13 14 try { 15 Thread.sleep(10000); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 20 long beginTime = CommonUtils.beginTime1; 21 if (CommonUtils.beginTime2 < CommonUtils.beginTime1) { 22 beginTime = CommonUtils.beginTime2; 23 } 24 25 long endTime = CommonUtils.endTime1; 26 if (CommonUtils.endTime2 > CommonUtils.endTime1) { 27 endTime = CommonUtils.endTime2; 28 } 29 30 System.out.println("耗时" + ((endTime - beginTime) / 1000) + " 秒"); 31 } 32 }
结果
1 begin task 2 begin task 3 长时间处理任务后从远程返回的值1 threadName=Thread-1 4 长时间处理任务后从远程返回的值1 threadName=Thread-0 5 长时间处理任务后从远程返回的值2 threadName=Thread-0 6 长时间处理任务后从远程返回的值2 threadName=Thread-0 7 end task 8 end task 9 耗时3 秒
这里是用的synchronized代码锁,如果换成方法锁
所有代码不变,仅更改Task类
1 package com.weishiyao.learn.day4.testSynchorized.ep2; 2 3 public class Task { 4 5 private String getData1; 6 private String getData2; 7 8 public synchronized void doLongTimeTask() { 9 try { 10 System.out.println("begin task"); 11 Thread.sleep(3000); 12 getData1 = "长时间处理任务后从远程返回的值1 threadName=" 13 + Thread.currentThread().getName(); 14 getData2 = "长时间处理任务后从远程返回的值2 threadName=" 15 + Thread.currentThread().getName(); 16 System.out.println(getData1); 17 System.out.println(getData2); 18 System.out.println("end task"); 19 } catch (InterruptedException e) { 20 // TODO Auto-generated catch block 21 e.printStackTrace(); 22 } 23 } 24 }
运行结果
1 begin task 2 长时间处理任务后从远程返回的值1 threadName=Thread-0 3 长时间处理任务后从远程返回的值2 threadName=Thread-0 4 end task 5 begin task 6 长时间处理任务后从远程返回的值1 threadName=Thread-1 7 长时间处理任务后从远程返回的值2 threadName=Thread-1 8 end task 9 耗时6 秒
可以得出结论,当一个线程访问object的synchronized同步代码块时,另一个线程依然可以访问非同步代码块,这样同步代码块就会比同步方法所花费更短的时间,可以得到更高的效率,在同步代码块中代码是同步的,不在同步代码块中代码是异步的。
二、synchronized代码块间的同步性
当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块的访问将被阻塞,因为synchronized使用的是一个“对象监视器”
ObjectService类
1 package com.weishiyao.learn.day4.testSynchorized.ep3; 2 3 public class ObjectService { 4 5 public void serviceMethodA() { 6 try { 7 synchronized (this) { 8 System.out 9 .println("A begin time=" + System.currentTimeMillis()); 10 Thread.sleep(2000); 11 System.out 12 .println("A end end=" + System.currentTimeMillis()); 13 } 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 } 18 19 public void serviceMethodB() { 20 synchronized (this) { 21 System.out.println("B begin time=" + System.currentTimeMillis()); 22 System.out.println("B end end=" + System.currentTimeMillis()); 23 } 24 } 25 }
ThreadA
1 package com.weishiyao.learn.day4.testSynchorized.ep3; 2 3 public class ThreadA extends Thread { 4 5 private ObjectService service; 6 7 public ThreadA(ObjectService service) { 8 super(); 9 this.service = service; 10 } 11 12 @Override 13 public void run() { 14 super.run(); 15 service.serviceMethodA(); 16 } 17 18 }
ThreadB
1 package com.weishiyao.learn.day4.testSynchorized.ep3; 2 3 public class ThreadB extends Thread { 4 private ObjectService service; 5 6 public ThreadB(ObjectService service) { 7 super(); 8 this.service = service; 9 } 10 11 @Override 12 public void run() { 13 super.run(); 14 service.serviceMethodB(); 15 } 16 }
Run
1 package com.weishiyao.learn.day4.testSynchorized.ep3; 2 3 public class Run { 4 5 public static void main(String[] args) { 6 ObjectService service = new ObjectService(); 7 8 ThreadA a = new ThreadA(service); 9 a.setName("a"); 10 a.start(); 11 12 ThreadB b = new ThreadB(service); 13 b.setName("b"); 14 b.start(); 15 } 16 17 }
结果
1 A begin time=1459077186249 2 A end end=1459077188249 3 B begin time=1459077188249 4 B end end=1459077188249
三、静态同步synchronized方法与synchronized(class)代码块
关键字synchronized还可以用在static静态方法上,如果这样写,那是对当前的java对应的Class类进行上锁
Service类
1 package com.weishiyao.learn.day4.staticSynchorized; 2 3 public class Service { 4 synchronized public static void printA() { 5 try { 6 System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入A"); 7 Thread.sleep(3000); 8 System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开A"); 9 } catch (Exception e) { 10 e.printStackTrace(); 11 } 12 } 13 14 synchronized public static void printB() { 15 try { 16 System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入B"); 17 Thread.sleep(3000); 18 System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开B"); 19 } catch (Exception e) { 20 e.printStackTrace(); 21 } 22 } 23 24 synchronized public void printC() { 25 try { 26 System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入C"); 27 Thread.sleep(3000); 28 System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开C"); 29 } catch (Exception e) { 30 e.printStackTrace(); 31 } 32 } 33 }
ThreadA
1 package com.weishiyao.learn.day4.staticSynchorized; 2 3 public class ThreadA extends Thread { 4 private Service service; 5 6 public ThreadA(Service service) { 7 super(); 8 this.service = service; 9 } 10 11 @SuppressWarnings("static-access") 12 @Override 13 public void run() { 14 service.printA(); 15 } 16 }
ThreadB、ThreadC类似ThreadA,不再列出
Run
1 package com.weishiyao.learn.day4.staticSynchorized; 2 3 public class Run { 4 public static void main(String[] args) { 5 Service service = new Service(); 6 ThreadA threadA = new ThreadA(service); 7 threadA.setName("A"); 8 threadA.start(); 9 ThreadB threadB = new ThreadB(service); 10 threadB.setName("B"); 11 threadB.start(); 12 ThreadC threadC = new ThreadC(service); 13 threadC.setName("C"); 14 threadC.start(); 15 } 16 }
结果
1 线程名称为:A在1459078101483进入A 2 线程名称为:C在1459078101490进入C 3 线程名称为:A在1459078104484离开A 4 线程名称为:B在1459078104484进入B 5 线程名称为:C在1459078104491离开C 6 线程名称为:B在1459078107484离开B
分析运行结果,A和B是同步运行,C是异步运行,异步的原因是持有不同的锁,一个是对象锁,另外一个是Class锁。
同步synchronized(class)代码块的作用和synchronized static方法的作用一样。
四、内置类与同步
OutClass
1 package com.weishiyao.learn.day4.syncClass.ep5; 2 3 public class OutClass { 4 static class InnerClass1 { 5 public void method1(InnerClass2 class2) { 6 String threadName = Thread.currentThread().getName(); 7 synchronized (class2) { 8 System.out.println(threadName 9 + " 进入InnerClass1类中的method1方法"); 10 for (int i = 0; i < 10; i++) { 11 System.out.println("i=" + i); 12 try { 13 Thread.sleep(100); 14 } catch (InterruptedException e) { 15 16 } 17 } 18 System.out.println(threadName 19 + " 离开InnerClass1类中的method1方法"); 20 } 21 } 22 23 public synchronized void method2() { 24 String threadName = Thread.currentThread().getName(); 25 System.out.println(threadName + " 进入InnerClass1类中的method2方法"); 26 for (int j = 0; j < 10; j++) { 27 System.out.println("j=" + j); 28 try { 29 Thread.sleep(100); 30 } catch (InterruptedException e) { 31 32 } 33 } 34 System.out.println(threadName + " 离开InnerClass1类中的method2方法"); 35 } 36 } 37 38 static class InnerClass2 { 39 public synchronized void method1() { 40 String threadName = Thread.currentThread().getName(); 41 System.out.println(threadName + " 进入InnerClass2类中的method1方法"); 42 for (int k = 0; k < 10; k++) { 43 System.out.println("k=" + k); 44 try { 45 Thread.sleep(100); 46 } catch (InterruptedException e) { 47 48 } 49 } 50 System.out.println(threadName + " 离开InnerClass2类中的method1方法"); 51 } 52 } 53 }
Run
1 package com.weishiyao.learn.day4.syncClass.ep5; 2 3 import com.weishiyao.learn.day4.syncClass.ep5.OutClass.InnerClass1; 4 import com.weishiyao.learn.day4.syncClass.ep5.OutClass.InnerClass2; 5 6 public class Run { 7 8 public static void main(String[] args) { 9 final InnerClass1 in1 = new InnerClass1(); 10 final InnerClass2 in2 = new InnerClass2(); 11 Thread t1 = new Thread(new Runnable() { 12 public void run() { 13 in1.method1(in2); 14 } 15 }, "T1"); 16 Thread t2 = new Thread(new Runnable() { 17 public void run() { 18 in1.method2(); 19 } 20 }, "T2"); 21 Thread t3 = new Thread(new Runnable() { 22 public void run() { 23 in2.method1(); 24 } 25 }, "T3"); 26 t1.start(); 27 t2.start(); 28 t3.start(); 29 } 30 }
结果
1 T2 进入InnerClass1类中的method2方法 2 T1 进入InnerClass1类中的method1方法 3 i=0 4 j=0 5 i=1 6 j=1 7 j=2 8 i=2 9 i=3 10 j=3 11 j=4 12 i=4 13 i=5 14 j=5 15 j=6 16 i=6 17 i=7 18 j=7 19 i=8 20 j=8 21 i=9 22 j=9 23 T2 离开InnerClass1类中的method2方法 24 T1 离开InnerClass1类中的method1方法 25 T3 进入InnerClass2类中的method1方法 26 k=0 27 k=1 28 k=2 29 k=3 30 k=4 31 k=5 32 k=6 33 k=7 34 k=8 35 k=9 36 T3 离开InnerClass2类中的method1方法
同步代码块synchronized(class2)对class2上锁后,其他线程只能以同步的方式调用class2中的静态同步方法
五、锁对象的改变
在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的;如果分别获得锁对象,这些线程之间就是异步的。
MyService
1 package com.weishiyao.learn.day4.syncClass.ep6; 2 3 public class MyService { 4 private String lock = "123"; 5 6 public void testMethod() { 7 try { 8 synchronized (lock) { 9 System.out.println(Thread.currentThread().getName() + " begin " 10 + System.currentTimeMillis()); 11 lock = "456"; 12 Thread.sleep(2000); 13 System.out.println(Thread.currentThread().getName() + " end " 14 + System.currentTimeMillis()); 15 } 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 } 20 21 }
ThreadA
1 package com.weishiyao.learn.day4.syncClass.ep6; 2 3 public class ThreadA extends Thread { 4 5 private MyService service; 6 7 public ThreadA(MyService service) { 8 super(); 9 this.service = service; 10 } 11 12 @Override 13 public void run() { 14 service.testMethod(); 15 } 16 }
ThreadB
package com.weishiyao.learn.day4.syncClass.ep6; public class ThreadB extends Thread { private MyService service; public ThreadB(MyService service) { super(); this.service = service; } @Override public void run() { service.testMethod(); } }
Run1
1 package com.weishiyao.learn.day4.syncClass.ep6; 2 3 public class Run1 { 4 5 public static void main(String[] args) throws InterruptedException { 6 7 MyService service = new MyService(); 8 9 ThreadA a = new ThreadA(service); 10 a.setName("A"); 11 12 ThreadB b = new ThreadB(service); 13 b.setName("B"); 14 15 a.start(); 16 Thread.sleep(50); 17 b.start(); 18 } 19 }
结果
1 A begin 1459080143796 2 B begin 1459080143846 3 A end 1459080145797 4 B end 1459080145846
因为50毫秒之后a取得的是锁"456"
重新改一下Run类
1 package com.weishiyao.learn.day4.syncClass.ep6; 2 3 public class Run2 { 4 5 public static void main(String[] args) throws InterruptedException { 6 7 MyService service = new MyService(); 8 9 ThreadA a = new ThreadA(service); 10 a.setName("A"); 11 12 ThreadB b = new ThreadB(service); 13 b.setName("B"); 14 15 a.start(); 16 b.start(); 17 } 18 }
结果
1 A begin 1459080318782 2 A end 1459080320782 3 B begin 1459080320782 4 B end 1459080322783
只要对象不变,即使对象的属性被改变,运行结果还是同步的
Service
1 package com.weishiyao.learn.day4.syncClass.ep7; 2 3 public class Service { 4 5 public void serviceMethodA(Userinfo userinfo) { 6 synchronized (userinfo) { 7 try { 8 System.out.println(Thread.currentThread().getName()); 9 userinfo.setUsername("abcabcabc"); 10 Thread.sleep(3000); 11 System.out.println("end! time=" + System.currentTimeMillis()); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 } 16 } 17 }
Userinfo
1 package com.weishiyao.learn.day4.syncClass.ep7; 2 3 public class Userinfo { 4 private String username; 5 private String password; 6 7 public Userinfo() { 8 super(); 9 } 10 11 public Userinfo(String username, String password) { 12 super(); 13 this.username = username; 14 this.password = password; 15 } 16 17 public String getUsername() { 18 return username; 19 } 20 21 public void setUsername(String username) { 22 this.username = username; 23 } 24 25 public String getPassword() { 26 return password; 27 } 28 29 public void setPassword(String password) { 30 this.password = password; 31 } 32 33 }
ThreadA
1 package com.weishiyao.learn.day4.syncClass.ep7; 2 3 public class ThreadA extends Thread { 4 5 private Service service; 6 private Userinfo userinfo; 7 8 public ThreadA(Service service, 9 Userinfo userinfo) { 10 super(); 11 this.service = service; 12 this.userinfo = userinfo; 13 } 14 15 @Override 16 public void run() { 17 service.serviceMethodA(userinfo); 18 } 19 20 }
ThreadB
1 package com.weishiyao.learn.day4.syncClass.ep7; 2 3 public class ThreadB extends Thread { 4 5 private Service service; 6 private Userinfo userinfo; 7 8 public ThreadB(Service service, 9 Userinfo userinfo) { 10 super(); 11 this.service = service; 12 this.userinfo = userinfo; 13 } 14 15 @Override 16 public void run() { 17 service.serviceMethodA(userinfo); 18 } 19 20 }
运行类
1 package com.weishiyao.learn.day4.syncClass.ep7; 2 3 public class Run { 4 5 public static void main(String[] args) { 6 7 try { 8 Service service = new Service(); 9 Userinfo userinfo = new Userinfo(); 10 11 ThreadA a = new ThreadA(service, userinfo); 12 a.setName("a"); 13 a.start(); 14 Thread.sleep(50); 15 ThreadB b = new ThreadB(service, userinfo); 16 b.setName("b"); 17 b.start(); 18 19 } catch (InterruptedException e) { 20 e.printStackTrace(); 21 } 22 23 } 24 }
结果
1 a 2 end! time=1459080585999 3 b 4 end! time=1459080589000