2012-10-21 67 views
1

请问有人能解释为什么这段代码是死锁。它似乎应该正常工作。请详细解释它。谢谢。Java中的多线程死锁

public class H extends Thread { 
    String info = ""; 
    public H (String info) { 
     this.info = info; 
    } 

    public synchronized void run() { 
     try { 
      while (true) { 
       System.out.println(info); 
       notify(); 
       wait(); 
      } 
     } catch (Exception e) {} 

    } 
    public static void main(String[] args) { 
      new H("0").start(); 
      new H("1").start(); 
    } 

}

+0

它究竟是如何死锁?它打印两个东西,但没有终止? –

+0

它打印而这就是卡在死锁 –

回答

5

每个线程同步上this(经由​​关键字上的方法),这是用于两个线程对象的不同。他们每个呼叫notifywait但他们不相互作用,因为this是不同的。因此,在第一次迭代中,他们都拨打wait并永远阻止,因为没有人会将其唤醒。

以下是我为使代码正常工作而进行的一些更改。注意共享静态字段,允许线程进行通信:

public class Test extends Thread { 
    String info = ""; 
    static final Object signal = new Object(); 
    static volatile String current = null; 

    public Test (String info) { 
     this.info = info; 
    } 

    public void run() { 
     try { 
      synchronized(signal) { 
       while (true) {         
        while(current.equals(info)) 
         signal.wait(); 
        System.out.println(info); 
        current = info; 
        signal.notify(); 
       } 
      } 
     } catch (Exception e) {} 

    } 

    public static void main(String[] args) { 
     Test.current = "0"; 
     new Test("0").start(); 
     new Test("1").start(); 
    } 
} 

有你原来的代码,我想让其他一些注意事项:

  • 你应该努力实现的,而不是延长ThreadRunnable 。这样给你更多的灵活性。
  • 不要吞下异常。
+0

+1因为这就是为什么他们永远不会完成,但这并非真正的死锁。当两个资源都被阻塞等待另一个资源完成时,就会出现死锁。这只是两个永久等待的资源。它是'while(true){}'的线程停放版本。 – yshavit

1

notify()只唤醒当前正在等待对象的线程。当你调用notify()时,任何情况下都不会有线程在等待。然后,当你呼叫等待时,你永远不会有任何通知()的代码。基本上,你不能从同一个线程通知一个线程,因为它必须等待。尝试通过等待一段时间后从主线程通知他们,看看会发生什么。

public class H extends Thread { 
    String info = ""; 
    public H (String info) { 
     this.info = info; 
    } 

    public synchronized void run() { 
     try { 
      while (true) { 
       System.out.println(info); 
       wait(); 
      } 
     } catch (Exception e) {} 

    } 
    public static void main(String[] args) throws Exception { 
      H a = new H("0").start(); 
      H b = new H("1").start(); 
      Thread.sleep(1000); 
      a.notify(); 
      b.notify(); 
    } 
} 

请注意,这两个线程都不会通知其他线程。等待对象只能等待它,而不是完全等级。

TL; DR:notify()没有做任何事,wait()创建死锁。

3

notifywait都呼吁Thread对象这是不同的,所以当一个线程到达wait,其他线程不会通知它,相反,每个线程通知本身。

的流动是非常(有可能是交织):

  1. 的ThreadA开始
  2. 的ThreadA通知了正在上ThreadA中的锁等待的对象
  3. 的ThreadA上ThreadA中的锁等待
  4. ThreadB开始
  5. ThreadB通知等待ThreadB锁的对象
  6. ThreadB在ThreadB的锁上等待

最终状态 - 两个线程正在等待,没有人通知他们。