学习互联网架构第三课(synchronized重入锁)

xiaoxiao2021-02-28  97

关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到了一个对象的锁后,再次请求此对象时是可以再次得到该对象的锁。关于重入锁的理解,大家可以参考http://blog.csdn.net/u012453843/article/details/72884920这篇博客进行学习。

      下面我们来看一个示例,如下所示:

package com.internet.thread; public class SyncDubbo1 { public synchronized void method1(SyncDubbo1 sd){ if(Thread.currentThread().getName().equals("t1")){ Thread t3 = new Thread(new Runnable() { @Override public void run() { sd.method2(); } },"t3"); t3.start(); System.out.println("线程t1的method1方法执行.."); method2(); System.out.println("线程t1的method1调用结束"); }else if(Thread.currentThread().getName().equals("t2")){ System.out.println("线程t2的method1方法执行.."); method2(); System.out.println("线程t2的method1调用结束"); } } public void method2() { if(Thread.currentThread().getName().equals("t1")){ System.out.println("线程t1的method2方法执行.."); method3(); System.out.println("线程t1的method2调用结束"); }else if(Thread.currentThread().getName().equals("t2")){ System.out.println("线程t2的method2方法执行.."); method3(); System.out.println("线程t2的method2调用结束"); }else if(Thread.currentThread().getName().equals("t3")){ System.out.println("线程t3的method2方法执行.."); method3(); System.out.println("线程t3的method2调用结束"); } } public void method3(){ if(Thread.currentThread().getName().equals("t1")){ System.out.println("线程t1的method3方法执行完毕"); }else if(Thread.currentThread().getName().equals("t2")){ System.out.println("线程t2的method3方法执行完毕"); }else if(Thread.currentThread().getName().equals("t3")){ System.out.println("线程t3的method3方法执行完毕"); } } public static void main(String[] args){ final SyncDubbo1 sd = new SyncDubbo1(); Thread t1 = new Thread(new Runnable() { @Override public void run() { sd.method1(sd); } },"t1"); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { sd.method1(sd); } },"t2"); t2.start(); } }         可以看到method2和method3没有添加synchronized关键字,运行结果如下(列出的只是一种运行结果,还有其他结果):

线程t1的method1方法执行.. 线程t3的method2方法执行.. 线程t1的method2方法执行.. 线程t3的method3方法执行完毕 线程t1的method3方法执行完毕 线程t3的method2调用结束 线程t1的method2调用结束 线程t1的method1调用结束 线程t2的method1方法执行.. 线程t2的method2方法执行.. 线程t2的method3方法执行完毕 线程t2的method2调用结束 线程t2的method1调用结束         可以看到线程t1和t3执行method2和method3的顺序是不固定的,这样就可能有问题,在处理可能出现线程问题的情况时,我们更希望线程执行的时候不要交叉执行,那么我们可以在method2和method3上加synchronized关键字,代码如下

package com.internet.thread; public class SyncDubbo1 { public synchronized void method1(SyncDubbo1 sd){ if(Thread.currentThread().getName().equals("t1")){ Thread t3 = new Thread(new Runnable() { @Override public void run() { sd.method2(); } },"t3"); t3.start(); System.out.println("线程t1的method1方法执行.."); method2(); System.out.println("线程t1的method1调用结束"); }else if(Thread.currentThread().getName().equals("t2")){ System.out.println("线程t2的method1方法执行.."); method2(); System.out.println("线程t2的method1调用结束"); } } public synchronized void method2() { if(Thread.currentThread().getName().equals("t1")){ System.out.println("线程t1的method2方法执行.."); method3(); System.out.println("线程t1的method2调用结束"); }else if(Thread.currentThread().getName().equals("t2")){ System.out.println("线程t2的method2方法执行.."); method3(); System.out.println("线程t2的method2调用结束"); }else if(Thread.currentThread().getName().equals("t3")){ System.out.println("线程t3的method2方法执行.."); method3(); System.out.println("线程t3的method2调用结束"); } } public synchronized void method3(){ if(Thread.currentThread().getName().equals("t1")){ System.out.println("线程t1的method3方法执行完毕"); }else if(Thread.currentThread().getName().equals("t2")){ System.out.println("线程t2的method3方法执行完毕"); }else if(Thread.currentThread().getName().equals("t3")){ System.out.println("线程t3的method3方法执行完毕"); } } public static void main(String[] args){ final SyncDubbo1 sd = new SyncDubbo1(); Thread t1 = new Thread(new Runnable() { @Override public void run() { sd.method1(sd); } },"t1"); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { sd.method1(sd); } },"t2"); t2.start(); } }          我们再执行main方法,运行结果如下

线程t1的method1方法执行.. 线程t1的method2方法执行.. 线程t1的method3方法执行完毕 线程t1的method2调用结束 线程t1的method1调用结束 线程t3的method2方法执行.. 线程t3的method3方法执行完毕 线程t3的method2调用结束 线程t2的method1方法执行.. 线程t2的method2方法执行.. 线程t2的method3方法执行完毕 线程t2的method2调用结束 线程t2的method1调用结束         可以看到线程t1执行完之后才执行的线程t3,最后执行的是线程t2,线程t1由方法method1要去执行由synchronized修饰的method2,直接便可以获取到锁,这种情况便是锁重入。如果synchronized不支持锁重入的话,会造成死锁的情况(method1还没执行完,要执行method2,method2不让获取锁的话,method1就执行不完了)。          上面说的是一种锁重入的场景,锁重入还有一种常见的情形,那就是父子类的情况,再看一个例子

package com.internet.thread; public class SyncDubbo2 { static class Main { public int i = 10; public synchronized void operationSup(){ try { i--; System.out.println("Main print i = "+i); Thread.sleep(100);//休息0.1秒 } catch (Exception e) { e.printStackTrace(); } } } static class Sub extends Main{ public synchronized void operationSub(){ try { while(i > 0){ i--; System.out.println("Sub print i= "+i); Thread.sleep(100); this.operationSup(); } } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args){ Thread t1 = new Thread(new Runnable() { @Override public void run() { Sub sub = new Sub(); sub.operationSub(); } }); t1.start(); } }         执行结果如下,可以看到Sub和Main类的方法交替执行,而这两个方法都有synchronized修饰,说明父子类的情况锁重入也是可以的。

Sub print i= 9 Main print i = 8 Sub print i= 7 Main print i = 6 Sub print i= 5 Main print i = 4 Sub print i= 3 Main print i = 2 Sub print i= 1 Main print i = 0

转载请注明原文地址: https://www.6miu.com/read-46339.html

最新回复(0)