2013-03-29 34 views
3

以下代码是在SCJP6书理解多线程

class ThreadA { 
    public static void main(String [] args) { 
     ThreadB b = new ThreadB(); 
     b.start(); 

     synchronized(b) { 
      try { 
       System.out.println("Waiting for b to complete..."); 
       b.wait(); 
      } catch (InterruptedException e) {} 
      System.out.println("Total is: " + b.total); 
     } 
    } 
} 

class ThreadB extends Thread { 
    int total; 

    public void run() { 
     synchronized(this) { 
      for(int i=0;i<100;i++) { 
       total += i; 
      } 
      notify(); 
     } 
    } 
} 

不会在前面的代码导致死锁既是螺纹a和b具有b上的锁(在相应的同步块)?

我错过了一些东西,但不太清楚它是什么。

+0

你试过吗?这管用吗?我认为它不会造成成本死锁 –

+0

附注:如果在这种情况下出现死锁,整个等待/通知机制将是一个完整而彻底的失败,完全没用。 – Dariusz

+2

为什么是-1?这对我来说似乎是合法的:| –

回答

4

这取决于。

wait方法的文档 -

造成当前线程等待,直到其他线程调用notify()方法或此对象的notifyAll的()方法。换句话说,这个方法的行为就好像它只是执行呼叫等待(0)一样。

当前线程必须拥有该对象的监视器。该线程发布 该监视器的所有权,并等待另一个线程通知 等待此对象监视器的线程通过调用notify方法或notifyAll方法的 唤醒。然后线程 等待,直到它可以重新获得显示器的所有权并恢复执行 。

所以,如果你认为这两种情况 -

  • 如果ThreadA沾到对象的锁b第一,它会等待,导致锁的释放,这将导致ThreadB继续是工作。
  • 如果ThreadB先得到锁定,那么它将继续它的工作,释放锁定,然后ThreadA将开始。接下来,ThreadA将等待对象锁b,这可能导致它永远等待。
+0

一个很好的答案。简而言之,就是要点。文档报价。使我相信再次;) – Dariusz

+0

虽然事实上,它错过了主线程可能永远不会完成的观点。 – assylias

+1

@assylias:是的,我错过了。在编辑和输入上述两种情况时遇到这种情况。现在可以了。 –

6

最可能的执行如下:

  • 有和b.start()之间稍有延迟的run方法正在执行
  • 因此主线程管理,以获取关于b锁并进入​​块
  • 然后等待b其中释放锁
  • run开始执行,监控是可用的(或将提供相当不久),因此它可以进入​​块
  • 当它完成它通知b,它可以停止等待
  • 主线程完成。

然而,根据线程调度,这不是不可能的run首先执行,在这种情况下,主线程可以永远等待b.wait()。例如,如果您通过在b.start()之后插入一个小的Thread.sleep(100)来帮助解决该问题,则应该观察该行为。底线:这是一个可能遇到活性问题的臭味代码(自锁可用以后,它本身不是死锁)。

+0

很好地捕捉到了执行顺序的错误,但是你并没有真正回答这个问题。 – Dariusz

+0

@Dariusz你是什么意思? – assylias

+0

问题是:“会导致僵局吗?”。我认为这是OP想知道的事情。我知道你提到等待释放锁定,但这不是一个直接的答案。仍然是一个很好的答案,我为其+1了。 – Dariusz