一道很有意思的java线程题

这几天看结城浩的《java多线程设计模式》,跟着做一些习题,有几道题目很有意思,记录下自己的体会。

  首先是题目(在原书212页,书尾有解答):

Java代码   收藏代码
  1. public class Main {  
  2.     public static void main(String[] args) {  
  3.         try {  
  4.             Blackhole.enter(new Object());  
  5.         } catch (InterruptedException e) {  
  6.             e.printStackTrace();  
  7.         }  
  8.     }  
  9. }  

 

Java代码   收藏代码
  1. public class Blackhole {      
  2.         public static void enter(Object obj) throws InterruptedException {  
  3.         System.out.println("1");  
  4.         magic(obj);  
  5.         System.out.println("2");  
  6.         synchronized (obj) {  
  7.             System.out.println("3");  
  8.         }  
  9.     }  
  10.   
  11.     private static void magic(Object obj){}  
  12. }  

 代码很简单,要求写出magic()代码,使得输出是

 

Java代码   收藏代码
  1. 1  
  2. 2  

 不能出现3.

 

 

  思路:很明显要想不输出3,magic()必须得到obj锁,且不能释放才行。我的答案:

 

Java代码   收藏代码
  1. private static void magic(final Object obj) throws InterruptedException {  
  2.     new Thread() {  
  3.         @Override  
  4.         public void run() {  
  5.             synchronized (obj) {  
  6.                 while (true) {  
  7.                 }  
  8.             }  
  9.         }  
  10.     }.start();  
  11.     Thread.sleep(100);//略停片刻,确保新线程能先于主线程得到obj锁,    
  12.                          //不加这句输出往往还是123    
  13.                          //这题的难点就在这里    
  14. }  

     显然sleep()用的很不专业吐舌头,那就来看作者的答案吧

 

Java代码   收藏代码
  1. private static void magic(final Object obj) throws InterruptedException {  
  2.     Thread thread = new Thread() {  
  3.         @Override  
  4.         public void run() {  
  5.             synchronized (obj) {  
  6.                 synchronized (this) {  
  7.                     this.setName("LockNow");  
  8.                     this.notifyAll();  
  9.                 }  
  10.                 while (true) {  
  11.                 }  
  12.             }  
  13.         }  
  14.     };  
  15.     synchronized (thread) {  
  16.         thread.setName("");  
  17.         thread.start();  
  18.         while (thread.getName().equals("")) {  
  19.             thread.wait();  
  20.         }  
  21.     }  
  22. }  

   作者的思路很巧妙,通过thread.name的值来处理2个线程的执行次序。

   1. 创建一个内部Thread实例thread,先不start()

   2. 然后由主线程获得thread锁,并启动thread线程,然后开始等待。

   3. thread线程会去获得obj锁,获得obj锁之后,该线程会修改自己name,并通知主线程。

   4. 主线程发现条件满足,继续执行

 

   刚看到答案,有个很大疑问,主线程获得thread锁之后,启动thread线程,而thread线程为了修改name,必须获得自己的锁(否则运行时会报错java.lang.IllegalMonitorStateException),这不死锁了吗?

 

   仔细一想又不会,因为新线程开启之后,如果新线程运行到synchronized (this)被阻挡而无法修改name,主线程肯定会进入wait,而wait时主线程释放thread锁,新线程就可继续往下跑。

  短短几行代码,线程之间同步协调环环相扣,不得不佩服作者的功力!

  

你可能感兴趣的:(java线程)