下面我们来看一个示例,如下所示:
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