2012-03-07 74 views
3

在我的計劃,我使用從併發:Condition.awaitNanos()不釋放鎖

private static final Lock lock = new ReentrantLock(); 

創建像這樣一個條件對象:

private static final Condition operationFinished = MyClass.lock.newCondition(); 

偶爾(因爲它總是與發生併發問題)我遇到以下行爲:

  1. Thread1獲得鎖
  2. Thread1調用operationFinished.awaitNanos() - 這應該暫停Thread1並釋放鎖。
  3. 線程2試圖將收購同一個鎖,但是在調試輸出顯示線程1仍然持有鎖!

根據文檔,此行爲是不可能的,因爲在awaitNanos()上Thread1首先釋放鎖,然後掛起。 如果它沒有釋放鎖,那麼它不會掛起,因此Thread2甚至永遠不可能試圖鎖住鎖。

有沒有人遇到過類似的東西嗎?這個錯誤發生在100次 - 但仍然表明我要麼沒有以正確的方式使用併發實用程序,要麼在java.utils.concurrent。*包中存在某種錯誤(我懷疑) 。

UPDATE:

針對彼得斯答案:

我注意到以下行爲:顯然,2個線程死鎖對方。我可以看到Thread2阻塞(等待鎖定),同時Thread1中的awaitNanos()也不會超時。

回答

1

取決於你如何查看此信息,我已經看到了其中一個對象上的多個線程wait()還是說,他們都持有相同的鎖的例子很多。這可能是堆棧跟蹤或監控不當。

假設你有線程1,其持有鎖,但在awaitNanos(),你有試圖獲得鎖()線程2,但有時Thread3持有鎖以及....

我會做一個jstack -l {pid}來檢查所有可能持有鎖的線程。

如果鎖死鎖,awaitLock(也不是等待())將不會返回,因爲它必須這樣做之前獲取鎖。 (除非它被中斷)

+0

Thx爲您的迴應!用更多信息更新了我的答案:由於我可以在'lock()'上看到Thread2阻塞,因此鎖定仍然由Thread1保存。 – quaylar 2012-03-07 15:15:51

+0

並且Thread1在awaitNanos()中是明確的嗎?你可以向我們展示這兩個線程和任何其他可能持有鎖的線程的堆棧跟蹤。例如從'jstack' – 2012-03-07 15:29:48

+0

我意識到當Thread1仍然不在awaitNanos()中時,可能有Thread2嘗試獲取鎖的可能性。但即使在這種情況下,Thread2也會阻塞,直到Thread1調用awaitNanos(),然後再獲取鎖... – quaylar 2012-03-07 15:34:05

1

你確定等待時間還沒有完成?如果等待一小段時間(例如幾百納秒),等待時間可能會在Thread2完全啓動之前到期,在這種情況下,Thread1可能會首先被重新激活。

+0

如果等待時間過期,我拋出異常,但是在發生此問題時沒有異常,並且沒有更多的調試輸出(如果Thread1在await()之後繼續,它應該仍然是輸出。 – quaylar 2012-03-07 15:31:27

+0

在拋出異常之前是否釋放了鎖?並且請記住,如果拋出異常的線程不是主線程,那麼它可能會觸發呼叫然後消失,除非你爲線程設置了未捕獲的異常處理程序 – 2012-03-07 15:42:18

+0

問題是,在目前的情況下,異常不會被拋出,所以awaitNanos()永遠不會返回......看起來像Thread1和線程2相互死鎖.. – quaylar 2012-03-07 15:55:51