1.同步锁的基本理解
当synchronized锁住一个对象后,别的线程如果也想拿到这个对象的锁,就必须等待这个线程执行完成释放锁,才能再次给对象加锁,这样才达到线程同步的目的。即使两个不同的代码段,都要锁同一个对象,那么这两个代码段也不能在多线程环境下同时运行。
2.使用时要明白两个问题
锁的对象是谁锁当前的持有者举例子说明: 例一:
public class Test { public synchronized void methodA(String param) { System.out.println("methodA's param :" + param); } public synchronized void methodB(){ methodA("methodB"); } public static void main(String[] args) { Test test = new Test(); test.methodB(); } }执行结果:
methodA’s param :methodB invoke
分析: ① methodB被调用因为有synchronized需要获得一个锁,锁的对象是test,也就是当前Test类的实例,而获得所得东西是线程,也就是当前线程拿到了test的锁(不是B方法获得了锁) ② methodB内部调用了methodA,此时A也加了synchronized,也需要获得一个锁,因为A和B都是Test类中的方法,所以当前线程要获得的锁的对象也是test,而当前线程执行B方法时已经持有了test对象的锁,所以会直接调用methodA,相当于方法A上没有加synchronized。
例二:
public class Test { public synchronized void methodA(String param) { System.out.println("methodA's param :" + param); } public synchronized void methodB(){ methodA("methodB"); } public static void main(String[] args) { Test test1 = new Test(); Test test2 = new Test(); test1.methodB(); test2.methodB(); } }运行结果:
methodA’s param :methodB methodA’s param :methodB
分析: ① 执行test1.methodB()当前线程会持有test1对象的锁 ② 执行test2.methodB()当前线程会持有test2对象的锁 ③ 当前线程持有了两把锁,但是锁的对象不一样,所以互相没有影响
例三:
public class Test { public synchronized void methodA(String param) { System.out.println("methodA's param :" + param); } public synchronized void methodB(){ methodA("methodB"); } public static void main(String[] args) { Test test = new Test(); ThreadTest thread1 = test.new ThreadTest("thread1"); ThreadTest thread2 = test.new ThreadTest("thread2"); thread1.start(); thread2.start(); } class ThreadTest extends Thread { public ThreadTest(String name){ super(name); } public void run() { Test test = new Test(); test.methodB(); } } }运行结果:
methodA’s param :methodB methodA’s param :methodB
分析:
① thread1先获取test的锁 ② thread1执行methodB ③ thread1执行methodA ④ thread1释放test的锁 ⑤ thread2获得test的锁 ⑥ thread2执行methodB ⑦ thread2执行methodA ⑧ thread2释放test的锁
总结:例三和例二结果一样,但是执行顺序却不同,另外synchronized还有很多种用法,在分析时一定要搞清楚哪个线程获得了哪个对象的锁,就很容易明白了。
