2014-04-25 29 views
1

我非常熟悉wait()/notify()信令方案在Java中的工作原理。但是,我意識到我看到的一些使用模式是Producer/Consumer方案的變體,或者Barrier的實現。我也看到了一些衆所周知的併發問題的實現,例如Dining Philosophers使用wait/notify,但顯然是用於教學目的。併發Java程序中的等待通知的非標準用法

此外,所有方案隨後的總是一個循環中調用wait()乖建議,和只透過循環,如下面的代碼後改變某些共享變量:

synchronized(mon) { 

    // #CP1 - Do not change variables here 

    while !(mycondition) { 
     try{ 
     // #CP2 Do not change variables here 
     mon.wait(); 
     } catch(catch (InterruptedException e) { e.printStackTrace(); } 
    } 

    // Condition satisfied - Now you can change!  
    makeOperation(); 

    // Tell others that you're done and exit 
    mon.notifyAll(); 
} 

我的問題是:爲還有其他使用wait()/notify()信號的模式比我引用的模式還要多嗎?你有沒有以非正統的方式使用它?爲什麼?這裏有一些更具體的問題可以幫助您:

  1. 您有沒有看過在退出循環之前改變共享變量的實現?在我的例子中,是否有理由在控制點#CP1#CP2中分配一些東西?
  2. 是否有某些情況下您選擇使用notify()而不是notifyAll()?儘管可能的性能增益,但你對此的確信不會導致一些死鎖?爲什麼?
  3. 有一些複雜的情況,其中等待條件mycondition依賴於多個線程,例如mycondition= a_ready && b_ready && c_ready
+0

我認爲在現代,使用'wait'和'notify' **是控制線程的非標準方式。可以認爲沒有什麼可以用它們完成,而不能用'java.util.concurrent'工具完成,也沒有邊緣效應。 – OldCurmudgeon

+0

@OldCurmudgeon:我同意自'java.util.concurrent'後'wait'和'notify'是非標準的。但有沒有人使用'java.util.concurrent.locks.Condition',這是'wait/notify'的高級替代品?如果是這樣,問題仍然存在。 – Pcgomes

+0

我認爲限制自己到'條件'是無效的。生產者/消費者架構現在可以通過各種處理一對多,多對一和一對一數據流的「BlockingQueue」類完美實現。除此之外,你可以進入'CyclicBarrier',atomics甚至'ForkJoinPool'來實現任何事情。您還可以獲得其他各種好吃的東西,例如'Futures'和'ThreadPool'。試圖比較舊的'wait/notify'和'j.u.concurrent'的豐富程度,比較粉筆和奶酪。 – OldCurmudgeon

回答

1
  1. 當然。一個例子是在#CP1你可以保留一個「等待名單」。我不確定我能否想到你可能會在#CP2上改變共享狀態,因爲通常while循環只存在於「虛假」喚醒的情況下(即你被喚醒但實際上不應該)。另外,對InterruptedException的處理通常是一個壞主意,因爲它不允許關閉線程(虛假喚醒是不同於獲取InterruptedException的)。
  2. 如果您知道只有一個服務員將繼續進行,則可以使用notify而不是notifyAll。如果有大量的等待線程,這可以高效得多。 但是,使用通知時有一些注意事項,您需要非常小心。一個服務員可以通知中斷,所以你的InterruptedException的處理需要重新通知(所以通知不會丟失)。這意味着即使你只打算讓一個服務員醒來,你也需要正確處理可以喚醒多個人的情況。一般來說,你必須確保你的代碼正確地導致另一個線程繼續進行,否則你最終會陷入死鎖狀態。
  3. 當然。你可以有一個標誌,表示一個給定的線程應該繼續,另一個標誌表示所有線程都應該中止(系統關閉或算法中止)。