文章目录
声明:
本博客是本人在学习《Java 多线程编程核心技术》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。
本博客已标明出处,如有侵权请告知,马上删除。
2.2 synchronized 同步语句块
用关键字 synchronized 声明方法在某些情况下是有弊端的,比如 A 线程调用同步方法执行一个较长时间的任务,那么 B 线程必须等待比较长的时间。这种情况下可以尝试使用 synchronized 同步代码块来解决问题。
synchronized 方法是对当前对象进行加锁,而 synchronized 代码块是对某一个对象进行加锁。
2.2.1 synchronized 方法的弊端
下面用一个示例来演示 synchronized 方法的弊端:
-
创建一个公共类
public class Task { private String getData1; private String getData2; synchronized public 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) { e.printStackTrace(); } } }
-
创建一个工具类
public class CommonUtils { public static long beginTime1; public static long beginTime2; public static long endTime1; public static long endTime2; }
-
创建两个自定义的线程类
public class MyThread1 extends Thread { private Task task; public MyThread1(Task task) { this.task = task; } @Override public void run() { super.run(); CommonUtils.beginTime1 = System.currentTimeMillis(); task.doLongTimeTask(); CommonUtils.endTime1 = System.currentTimeMillis(); } }
public class MyThread1_2 extends Thread { private Task task; public MyThread1_2(Task task) { this.task = task; } @Override public void run() { super.run(); CommonUtils.beginTime2 = System.currentTimeMillis(); task.doLongTimeTask(); CommonUtils.endTime2 = System.currentTimeMillis(); } }
-
测试类
public class MyThread1Test { public static void main(String[] args) { Task task = new Task(); MyThread1 myThread1 = new MyThread1(task); myThread1.start(); MyThread1_2 myThread1_2 = new MyThread1_2(task); myThread1_2.start(); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } long beginTime = CommonUtils.beginTime1; if (CommonUtils.beginTime1 > CommonUtils.beginTime2) { beginTime = CommonUtils.beginTime2; } long endTime = CommonUtils.endTime1; if (CommonUtils.endTime1 < CommonUtils.endTime2) { 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 秒
分析:在使用 synchronized 关键字来声明方法 synchronized public void doLongTimeTask() 时,从运行时间上来看,弊端很明显
2.2.2 synchronized 同步代码块的使用
当两个并发线程访问同一个对象 Object 中的 synchronized(this) 同步代码块时,一段时间只能有一个线程被执行,另一个线程必须等待当前线程执行完这个代码块后才执行该代码块。
下面通过一个示例来演示 synchronized 同步代码块的使用:
-
创建一个公共类
public class ObjectService { public void serviceMethod() { try { synchronized (this) { System.out.println("begin time = "+ System.currentTimeMillis()); Thread.sleep(2000); System.out.println("end time = "+ System.currentTimeMillis()); } } catch (InterruptedException e) { e.printStackTrace(); } } }
-
创建两个自定义的线程类
public class MyThread2 extends Thread { private ObjectService objectService; public MyThread2(ObjectService objectService) { this.objectService = objectService; } @Override public void run() { super.run(); objectService.serviceMethod(); } }
public class MyThread2_2 extends Thread { private ObjectService objectService; public MyThread2_2(ObjectService objectService) { this.objectService = objectService; } @Override public void run() { super.run(); objectService.serviceMethod(); } }
-
测试类
public class MyThread2Test { public static void main(String[] args) { ObjectService objectService = new ObjectService(); MyThread2 myThread2 = new MyThread2(objectService); myThread2.start(); MyThread2_2 myThread2_2 = new MyThread2_2(objectService); myThread2_2.start(); } }
运行结果
begin time = 1574418400128 end time = 1574418402128 begin time = 1574418402128 end time = 1574418404129
2.2.3 用同步代码块解决同步方法的弊端
上面介绍了 synchronized 同步代码块的使用,但执行的效率还是没有提高,如何使用 synchronized 同步代码块解决同步方法的弊端呢?
下面通过一个示例来演示使用 synchronized 同步代码块解决同步方法的弊端:
-
修改 2.2.1 中的公共类
public class Task { private String getData1; private String getData2; public void doLongTimeTask() { try { System.out.println("begin task"); Thread.sleep(3000); String privateGetData1 = " 长时间处理任务后从远程返回的值1,threadName = " + Thread.currentThread().getName(); String privateGetData2 = " 长时间处理任务后从远程返回的值2,threadName = " + Thread.currentThread().getName(); synchronized (this) { getData1 = privateGetData1; getData2 = privateGetData2; } System.out.println(getData1); System.out.println(getData2); System.out.println("end task"); } catch (InterruptedException e) { e.printStackTrace(); } } }
-
再次运行,得到运行结果如下
begin task begin task 长时间处理任务后从远程返回的值1,threadName = Thread-0 长时间处理任务后从远程返回的值2,threadName = Thread-1 end task 长时间处理任务后从远程返回的值1,threadName = Thread-1 长时间处理任务后从远程返回的值2,threadName = Thread-1 end task 耗时:3 秒
分析:当一个线程访问 object 的一个 synchronized(this) 同步代码块时,另一个线程仍然可以访问该 object 对象中的非 synchronized(this) 同步代码块
2.2.4 一半异步,一半同步
下面一个实验说明:不在 synchronized 代码块中就是异步执行,在 synchronized 代码块中就是同步执行
-
创建一个公共类
public class Task2 { public void doLongTimeTask() { for (int i = 0; i < 10; i++) { System.out.println("no synchronized threadName = " + Thread.currentThread().getName() + " i = " + i); } synchronized (this) { for (int i = 0; i < 10; i++) { System.out.println("synchronized threadName = " + Thread.currentThread().getName() + " i = " + i); } } } }
-
创建两个自定义的线程类
public class MyThread3 extends Thread { private Task2 task2; public MyThread3(Task2 task2) { this.task2 = task2; } @Override public void run() { super.run(); task2.doLongTimeTask(); } }
public class MyThread3_2 extends Thread { private Task2 task2; public MyThread3_2(Task2 task2) { this.task2 = task2; } @Override public void run() { super.run(); task2.doLongTimeTask(); } }
-
测试类
public class MyThread3Test { public static void main(String[] args) { Task2 task2 = new Task2(); MyThread3 myThread3 = new MyThread3(task2); myThread3.start(); MyThread3_2 myThread3_2 = new MyThread3_2(task2); myThread3_2.start(); } }
运行结果
no synchronized threadName = Thread-0 i = 0 no synchronized threadName = Thread-0 i = 1 no synchronized threadName = Thread-0 i = 2 no synchronized threadName = Thread-0 i = 3 no synchronized threadName = Thread-1 i = 0 no synchronized threadName = Thread-1 i = 1 no synchronized threadName = Thread-1 i = 2 no synchronized threadName = Thread-1 i = 3 no synchronized threadName = Thread-1 i = 4 no synchronized threadName = Thread-1 i = 5 no synchronized threadName = Thread-1 i = 6 no synchronized threadName = Thread-1 i = 7 no synchronized threadName = Thread-1 i = 8 no synchronized threadName = Thread-1 i = 9 synchronized threadName = Thread-1 i = 0 synchronized threadName = Thread-1 i = 1 synchronized threadName = Thread-1 i = 2 synchronized threadName = Thread-1 i = 3 synchronized threadName = Thread-1 i = 4 synchronized threadName = Thread-1 i = 5 synchronized threadName = Thread-1 i = 6 no synchronized threadName = Thread-0 i = 4 synchronized threadName = Thread-1 i = 7 no synchronized threadName = Thread-0 i = 5 synchronized threadName = Thread-1 i = 8 synchronized threadName = Thread-1 i = 9 no synchronized threadName = Thread-0 i = 6 no synchronized threadName = Thread-0 i = 7 no synchronized threadName = Thread-0 i = 8 no synchronized threadName = Thread-0 i = 9 synchronized threadName = Thread-0 i = 0 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
2.2.5 synchronized 代码块间的同步性
当一个线程访问 object 的一个 synchronized(this) 同步代码块时,其他线程对 object 中所有其它 synchronized(this) 同步代码块的访问将被阻塞。这说明 synchronized 使用的 “对象监视器” 是一个。
下面通过一个示例来演示:
-
创建一个公共类
public class ObjectService2 { public void serviceMethodA() { try { synchronized (this) { System.out.println("A begin time = " + System.currentTimeMillis()); Thread.sleep(1000); System.out.println("A end time = " + System.currentTimeMillis()); } } catch (InterruptedException e) { e.printStackTrace(); } } public void serviceMethodB() { synchronized (this) { System.out.println("B begin time = " + System.currentTimeMillis()); System.out.println("B end time = " + System.currentTimeMillis()); } } }
-
创建两个自定义的线程类
public class MyThread4 extends Thread { private ObjectService2 objectService2; public MyThread4(ObjectService2 objectService2) { this.objectService2 = objectService2; } @Override public void run() { super.run(); objectService2.serviceMethodA(); } }
public class MyThread4_2 extends Thread { private ObjectService2 objectService2; public MyThread4_2(ObjectService2 objectService2) { this.objectService2 = objectService2; } @Override public void run() { super.run(); objectService2.serviceMethodB(); } }
-
测试类
public class MyThread4Test { public static void main(String[] args) { ObjectService2 objectService2 = new ObjectService2(); MyThread4 myThread4 = new MyThread4(objectService2); myThread4.start(); MyThread4_2 myThread4_2 = new MyThread4_2(objectService2); myThread4_2.start(); } }
运行结果
A begin time = 1574423146307 A end time = 1574423147309 B begin time = 1574423147309 B end time = 1574423147309
分析:两个同步代码块按顺序执行
2.2.6 验证同步 synchronized(this) 代码块是锁定当前对象的
和 synchronized 方法一样,synchronized(this) 代码块也是锁定当前对象的
下面通过一个示例来演示:
-
创建一个公共类
public class Task3 { public void otherMethod() { System.out.println("run otherMethod..."); } public void doLongTimeTask() { try { synchronized (this) { for (int i = 0; i < 10; i++){ System.out.println(i); Thread.sleep(500); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
-
创建两个自定义的线程类
public class MyThread5 extends Thread { private Task3 task3; public MyThread5(Task3 task3) { this.task3 = task3; } @Override public void run() { super.run(); task3.doLongTimeTask(); } }
public class MyThread5_2 extends Thread { private Task3 task3; public MyThread5_2(Task3 task3) { this.task3 = task3; } @Override public void run() { super.run(); task3.otherMethod(); } }
-
测试类
public class MyThread5Test { public static void main(String[] args) { Task3 task3 = new Task3(); MyThread5 myThread5 = new MyThread5(task3); myThread5.start(); MyThread5_2 myThread5_2 = new MyThread5_2(task3); myThread5_2.start(); } }
运行结果
0 run otherMethod... 1 2 3 4 5 6 7 8 9
分析:myThread5 线程先持有了 Task3 对象的 Lock 锁,myThread5_2 线程可以以异步的方式调用 Task3 对象中的非 synchronized 类型的方法 otherMethod()
接下来把 Task3 对象中的非 synchronized 类型的方法 otherMethod() 上锁,再次运行:
-
把 Task3 对象中的非 synchronized 类型的方法 otherMethod() 上锁
public class Task3 { synchronized public void otherMethod() { System.out.println("run otherMethod..."); } public void doLongTimeTask() { try { synchronized (this) { for (int i = 0; i < 10; i++){ System.out.println(i); Thread.sleep(500); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
-
再次运行,运行结果如下
0 1 2 3 4 5 6 7 8 9 run otherMethod...
分析:synchronized(this) 代码块和 synchronized 方法同步执行,这说明和 synchronized 方法一样,synchronized(this) 代码块也是锁定当前对象的
2.2.7 将任意对象作为对象监视器
在前面的学习中,使用 synchronized(this) 格式来同步代码块,其实 Java 还支持对 “任意对象” 作为 “对象监视器” 来实现同步的功能。这个 “任意对象” 大多数是实例变量及方法的参数,使用格式为 synchronized(非 this 对象)。
在多个线程持有 “对象监视器” 为同一个对象的前提下,同一时间只有一个线程可以执行 synchronized(非 this 对象 x) 同步代码块中的代码,下面通过一个示例来演示:
-
创建一个公共类
public class Service { private String username; private String password; private String anyString = new String(); public void setUsernameAndPassword(String username, String password) { try { synchronized (anyString) { System.out.println("threadName = " + Thread.currentThread().getName() +" begin time = " + System.currentTimeMillis()); this.username = username; Thread.sleep(3000); this.password = password; System.out.println("threadName = " + Thread.currentThread().getName() +" end time = " + System.currentTimeMillis()); } } catch (InterruptedException e) { e.printStackTrace(); } } }
-
创建两个自定义的线程类
public class MyThread6 extends Thread { private Service service; public MyThread6(Service service) { this.service = service; } @Override public void run() { super.run(); service.setUsernameAndPassword("A","AA"); } }
public class MyThread6_2 extends Thread { private Service service; public MyThread6_2(Service service) { this.service = service; } @Override public void run() { super.run(); service.setUsernameAndPassword("B","BB"); } }
-
测试类
public class MyThread6Test { public static void main(String[] args) { Service service = new Service(); MyThread6 myThread6 = new MyThread6(service); myThread6.setName("A"); myThread6.start(); MyThread6_2 myThread6_2 = new MyThread6_2(service); myThread6_2.setName("B"); myThread6_2.start(); } }
运行结果
threadName = A begin time = 1574427244475 threadName = A end time = 1574427247476 threadName = B begin time = 1574427247476 threadName = B end time = 1574427250476
使用 synchronized(非 this 对象 x) 同步代码块时,对象监视器必须是同一个对象,否则运行的结果就是异步调用了,下面通过一个示例来演示:
-
修改 Service 类
public class Service { private String username; private String password; public void setUsernameAndPassword(String username, String password) { try { String anyString = new String(); synchronized (anyString) { System.out.println("threadName = " + Thread.currentThread().getName() + " begin time = " + System.currentTimeMillis()); this.username = username; Thread.sleep(3000); this.password = password; System.out.println("threadName = " + Thread.currentThread().getName() + " end time = " + System.currentTimeMillis()); } } catch (InterruptedException e) { e.printStackTrace(); } } }
-
再次运行,运行结果如下
threadName = A begin time = 1574428254678 threadName = B begin time = 1574428254679 threadName = A end time = 1574428257680 threadName = B end time = 1574428257681
锁非 this 对象具有一定的优点:如果一个类中有很多个 synchronized 同步方法,这时虽然能实现同步,但会受到阻塞,所以影响运行效率;但如果使用同步代码块锁非 this 对象,则 synchronized(非 this 对象) 代码块的程序与 synchronized 同步方法是异步调用的。不与其他锁 this 同步方法争抢 this 锁,则可以大大提高运行效率。
下面通过一个示例来演示 synchronized(非 this 对象) 与 synchronized 同步方法是异步调用的:
-
创建一个公共类
public class Service2 { private String anyString = new String(); public void a() { try { synchronized (anyString) { System.out.println("a begin"); Thread.sleep(3000); System.out.println("a end"); } } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void b() { System.out.println("b begin"); System.out.println("b end"); } }
-
创建两个自定义的线程类
public class MyThread7 extends Thread { private Service2 service2; public MyThread7(Service2 service2) { this.service2 = service2; } @Override public void run() { super.run(); service2.a(); } }
public class MyThread7_2 extends Thread { private Service2 service2; public MyThread7_2(Service2 service2) { this.service2 = service2; } @Override public void run() { super.run(); service2.b(); } }
-
测试类
public class MyThread7Test { public static void main(String[] args) { Service2 service2 = new Service2(); MyThread7 myThread7 = new MyThread7(service2); myThread7.start(); MyThread7_2 myThread7_2 = new MyThread7_2(service2); myThread7_2.start(); } }
运行结果
a begin b begin b end a end
分析:由于对象监视器不同,所以运行结果就是异步的
使用 “synchronized(非 this 对象 x)同步代码块" 格式也可以解决 “脏读问题”。但在解决脏读问题之前,先做一个实验,实验的目标是验证多个线程调用同一个方法是随机的。
-
创建一个公共类
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 方法"); } }
-
创建两个自定义的线程类
public class MyThread8 extends Thread { private MyList myList; public MyThread8(MyList myList) { this.myList = myList; } @Override public void run() { super.run(); for (int i = 0; i < 10; i++) { myList.add("ThreadA"+i); } } }
public class MyThread8_2 extends Thread { private MyList myList; public MyThread8_2(MyList myList) { this.myList = myList; } @Override public void run() { super.run(); for (int i = 0; i < 10; i++) { myList.add("ThreadB"+i); } } }
-
测试类
public class MyThread8Test { public static void main(String[] args) { MyList myList = new MyList(); MyThread8 myThread8 = new MyThread8(myList); myThread8.setName("A"); myThread8.start(); MyThread8_2 myThread8_2 = new MyThread8_2(myList); myThread8_2.setName("B"); myThread8_2.start(); } }
运行结果
ThreadName = A 执行了 add 方法 ThreadName = A 退出了 add 方法 ThreadName = B 执行了 add 方法 ThreadName = B 退出了 add 方法 ThreadName = A 执行了 add 方法 ThreadName = A 退出了 add 方法 ThreadName = B 执行了 add 方法 ThreadName = B 退出了 add 方法 ThreadName = B 执行了 add 方法 ThreadName = B 退出了 add 方法 ThreadName = A 执行了 add 方法 ThreadName = A 退出了 add 方法 ThreadName = B 执行了 add 方法 ThreadName = B 退出了 add 方法 ThreadName = B 执行了 add 方法 ThreadName = B 退出了 add 方法 ThreadName = A 执行了 add 方法 ThreadName = A 退出了 add 方法 ThreadName = B 执行了 add 方法 ThreadName = B 退出了 add 方法 ThreadName = B 执行了 add 方法 ThreadName = B 退出了 add 方法 ThreadName = A 执行了 add 方法 ThreadName = A 退出了 add 方法 ThreadName = B 执行了 add 方法 ThreadName = B 退出了 add 方法 ThreadName = A 执行了 add 方法 ThreadName = A 退出了 add 方法 ThreadName = A 执行了 add 方法 ThreadName = A 退出了 add 方法 ThreadName = B 执行了 add 方法 ThreadName = B 退出了 add 方法 ThreadName = A 执行了 add 方法 ThreadName = A 退出了 add 方法 ThreadName = A 执行了 add 方法 ThreadName = A 退出了 add 方法 ThreadName = A 执行了 add 方法 ThreadName = A 退出了 add 方法 ThreadName = B 执行了 add 方法 ThreadName = B 退出了 add 方法
分析:从运行结果上来看,同步方法中的程序是同步执行的,但线程 A 和线程 B 的执行却是异步的,这就有可能出现脏读的环境。
下面通过一个示例来演示出现脏读的情况:
-
创建一个公共类
public class MyList2 { private List list = new ArrayList(); synchronized public void add(String username) { list.add(username); } synchronized public int getSize() { return list.size(); } }
-
创建一个业务类
public class MyService { public void addService(MyList2 myList2, String username) { try { if (myList2.getSize() < 1) { Thread.sleep(2000); myList2.add(username); } } catch (InterruptedException e) { e.printStackTrace(); } } }
-
创建两个自定义的线程类
public class MyThread9 extends Thread { private MyList2 myList2; public MyThread9(MyList2 myList2) { this.myList2 = myList2; } @Override public void run() { super.run(); MyService myService = new MyService(); myService.addService(myList2,"A"); } }
public class MyThread9_2 extends Thread{ private MyList2 myList2; public MyThread9_2(MyList2 myList2) { this.myList2 = myList2; } @Override public void run() { super.run(); MyService myService = new MyService(); myService.addService(myList2,"B"); } }
-
测试类
public class MyThread9Test { public static void main(String[] args) throws InterruptedException { MyList2 myList2 = new MyList2(); MyThread9 myThread9 = new MyThread9(myList2); myThread9.start(); MyThread9_2 myThread9_2 = new MyThread9_2(myList2); myThread9_2.start(); Thread.sleep(6000); System.out.println(myList2.getSize()); } }
运行结果
2
分析:脏读出现了。出现原因是两个线程异步执行 addService 方法中的代码,解决办法就是 ”同步化“
下面通过一个示例解决脏读问题:
-
修改 MyService
public class MyService { public void addService(MyList2 myList2, String username) { try { synchronized (myList2) { if (myList2.getSize() < 1) { Thread.sleep(2000); myList2.add(username); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
-
再次运行,运行结果如下
1
分析:由于 list 参数对象在项目中是一份实例,是单例的,而且也正需要对 list 参数的 getSize() 方法做同步的调用,所以就对 list 参数进行同步处理
2.2.8 细化验证 3 个结论
“synchronized(非 this 对象 x)” 格式的写法是将 x 对象本身作为 ”对象监视器“,这样就可以得出以下三个结论:
-
当多个线程同时执行 synchronized(x){} 同步代码块时呈同步效果
-
当其他线程执行 x 对象中的 synchronized 同步方法时呈同步效果
-
当其他线程执行 x 对象中的 synchronized(this) 方法时也呈现同步效果
下面验证第 1 个结论:
当多个线程同时执行 synchronized(x){} 同步代码块时呈同步效果
-
创建一个公共类
public class MyObject { }
-
创建一个业务类
public class Service3 { public void testMethod1(MyObject myObject) { synchronized (myObject) { try { System.out.println("testMethod1 begin" + " run threadName = " + Thread.currentThread().getName()); Thread.sleep(2000); System.out.println("testMethod1 end" + " run threadName = " + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } }
-
创建两个自定义的线程类
public class MyThread10 extends Thread { private MyObject myObject; private Service3 service3; public MyThread10(MyObject myObject, Service3 service3) { this.myObject = myObject; this.service3 = service3; } @Override public void run() { super.run(); service3.testMethod1(myObject); } }
public class MyThread10_2 extends Thread { private MyObject myObject; private Service3 service3; public MyThread10_2(MyObject myObject, Service3 service3) { this.myObject = myObject; this.service3 = service3; } @Override public void run() { super.run(); service3.testMethod1(myObject); } }
-
测试类
public class MyThread10Test { public static void main(String[] args) { MyObject myObject = new MyObject(); Service3 service3 = new Service3(); MyThread10 myThread10 = new MyThread10(myObject, service3); myThread10.setName("A"); myThread10.start(); MyThread10_2 myThread10_2 = new MyThread10_2(myObject, service3); myThread10_2.setName("B"); myThread10_2.start(); } }
运行结果
testMethod1 begin run threadName = A testMethod1 end run threadName = A testMethod1 begin run threadName = B testMethod1 end run threadName = B
分析:同步的原因是因为使用了同一个对象监视器
下面验证第 2 个结论:
当其他线程执行 x 对象中的 synchronized 同步方法时呈同步效果
-
创建一个公共类
public class MyObject2 { synchronized public void speedPrintString() { System.out.println("speedPrintString begin" + "run threadName = " + Thread.currentThread().getName()); System.out.println("speedPrintString end" + "run threadName = " + Thread.currentThread().getName()); } }
-
创建一个业务类
public class Service4 { public void testMethod1(MyObject2 myObject2) { synchronized (myObject2) { try { System.out.println("testMethod1 begin" + " run threadName = " + Thread.currentThread().getName()); Thread.sleep(2000); System.out.println("testMethod1 end" + " run threadName = " + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } }
-
创建两个自定义的线程类
public class MyThread11 extends Thread { private Service4 service4; private MyObject2 myObject2; public MyThread11(Service4 service4, MyObject2 myObject2) { this.service4 = service4; this.myObject2 = myObject2; } @Override public void run() { super.run(); service4.testMethod1(myObject2); } }
public class MyThread11_2 extends Thread { private MyObject2 myObject2; public MyThread11_2(MyObject2 myObject2) { this.myObject2 = myObject2; } @Override public void run() { super.run(); myObject2.speedPrintString(); } }
-
测试类
public class MyThread11Test { public static void main(String[] args) { MyObject2 myObject2 = new MyObject2(); Service4 service4 = new Service4(); MyThread11 myThread11 = new MyThread11(service4, myObject2); myThread11.setName("A"); myThread11.start(); MyThread11_2 myThread11_2 = new MyThread11_2(myObject2); myThread11_2.setName("B"); myThread11_2.start(); } }
运行结果
testMethod1 begin run threadName = A testMethod1 end run threadName = A speedPrintString beginrun threadName = B speedPrintString endrun threadName = B
下面验证第 3 个结论:
当其他线程执行 x 对象中的 synchronized(this) 方法时也呈现同步效果
-
修改 MyObject2
public class MyObject2 { public void speedPrintString() { synchronized (this) { System.out.println("speedPrintString begin" + "run threadName = " + Thread.currentThread().getName()); System.out.println("speedPrintString end" + "run threadName = " + Thread.currentThread().getName()); } } }
-
再次运行,运行结果如下
testMethod1 begin run threadName = A testMethod1 end run threadName = A speedPrintString beginrun threadName = B speedPrintString endrun threadName = B