synchronized是多线程的入门,基础通常都很重要。synchronized更是如此
现在我们说一下synchronized修饰的方法的关键点和注意项。通过例子阐述原理
如果你拜读了java官方文档,你会知道synchronized方法也有锁(类似现实中的锁),那么它的锁(类似现实中的锁)是什么呢,下面通过代码和运行结果来找出答案
结构简述:
定义了一个资源PrintDemo3,一个线程类ThreadDemo3,一个测试类TestThread,在测试类中创建两个线程对象,两个线程对象都通过run方法访问资源PrintDemo.printCount方法
第一种场景:资源加锁在synchronized方法上
序幕1:
上面代码在PrintDemo3.printCount()上加了synchronized修饰符,表示这个方法是加锁了的。之后定义了两个PrintDemo3对象PD、PD3和两个ThreadDemo3线程对象T1、T2,并把PD、PD3分别传给T1、T2,见test1方法
运行后查看结果:
从结果得出,资源被两个线程同时访问了,synchronized方法的锁没有起作用。原因我们稍后再说,稍稍改一下代码
序幕2:
改一下代码:ThreadDemo3 T2 = new ThreadDemo3( “Thread - 2 “, PD3 ) 中的PD3改为PD
修改代码后运行,查看结果
从结果得出,实现了资源被线程独享
第一幕和第二幕代码的不同处只有传给两个线程的PrintDemo3对象不同。第一幕中两个线程T1、T2分别传递了PD、PD3。而第二幕中两个线程T1、T2都传递了PD。所以可以猜想,造成结果不同的原因也是由于锁(类似现实中的锁)的不同引起的。而修饰方法的synchronized的锁(类似现实中的锁)是synchronized方法所在类的对象实例,相当于synchronized方法等于方法里的synchronized(this)代码块,这里的this就是synchronized方法所在类的对象实例。
为了验证这个猜想,看第二种场景
第二种场景:资源加锁在方法内的synchronized(this)代码块上
场景二的代码与场景一99%是一样的,不同之处在PrintDemo3.printCount()方法上,把方法修饰符synchronized移到了此方法内,并把this作为synchronized的锁(类似现实中的锁)
序幕3:
两个线程T1、T2分别传递了PD、PD3
运行test1()方法并查看结果:
序幕4:
修改test1()方法代码为:
也就是两个线程T1、T2都传递了PD
运行test1()方法并查看结果:
结论:
synchronized方法等于方法中加入synchronized(this)代码块,也就是synchronized修饰方法时,synchronized的锁(类似现实中的锁)是调用这个方法的类的对象实例,如PD.printCount(),此时synchronized锁就是PD;而PD3.printCount(),此时synchronized锁就是PD3