2011-12-18 66 views
2

有n個線程可以訪問的單例類。
每個線程加載此類的實例並在一個循環中從此類調用一個方法。執行線程「one by one」

我必須控制執行的流程,以便每個線程都可以調用方法一和暫停,只有在所有線程調用該方法後才能恢復工作。線程可以按任意順序調用方法,只需要在移動循環之前執行一次方法。

這是我嘗試做:

在螺紋:

while (some condition){ 
    ObjectType obj = theSingleton.getInstance().getSharedObject(); 
    obj.SomeMethod(threadID); 
    if (obj.waitisneeded()) 
    synchronized (obj) { 
     obj.wait(); 
    } 
} 

我在的someMethod做:

public synchronized void SomeMethod(String threadID) { 
hashMap.put(threadID,true); 
some job here 
} 

和waitisneeded:

public synchronized boolean waitisneeded(){ 
{ 

    Iterator iter = hashMap.entrySet().iterator(); 

    boolean alldone = false; 

    while (iter.hasNext()) { 
     Map.Entry me = (Map.Entry) iter.next(); 
     String key = me.getKey().toString(); 
     alldone = (Boolean)me.getValue(); 

     if(!alldone) { 
    return false; 
     } 
    } 

    //set all values to false 
iter = hashMap.entrySet().iterator(); 
while (iter.hasNext()) { 
    Map.Entry me = (Map.Entry) iter.next(); 
    String key = me.getKey().toString(); 
    me.setValue(false);  
}  
this.notifyAll(); 
return true;    

運行這讓我感到意外編輯結果和死鎖。

我該如何解決?

注意:我無法改變線程的創建方式,我只能改變這些方法! (加在線程那裏等待是while循環)

+0

待辦事項你知道每個調用'obj.SomeMethod()'之前創建了多少個線程? – 2011-12-18 22:21:31

+0

你怎麼知道什麼時候「所有期望的線程現在稱爲單例」的時間點已經達到? – 2011-12-18 22:30:25

+0

@TheScrumMeister Scrum Meister是的,我知道線程數 – kenny 2011-12-19 05:11:52

回答

2

如果你知道線程數,你可以使用一個CyclicBarrier

static final CyclicBarrier barrier = new CyclicBarrier(numberOfThreads); 

然後,在點要在其中進行的所有主題等待別人,你叫:

​​

如果有還未到達該行一個線程,該線程調用await()將阻塞。一旦所有線程都到達並致電await(),它們將全部恢復。

每次你必須建立一些同步機制時,一定要檢查包java.util.concurrent。那裏有許多精彩的課程,由專家創建。大多數情況下,你不需要自定義的東西,如果你這樣做,在同一個包中有一些類將使得它幾乎不需要直接使用等待/通知 - 並且相信我,你想避免使用這些方法直接;正如你所看到的,你很容易陷入僵局!

+0

我認爲CyclicBarrier有問題,因爲var是靜態的。在我的應用程序中,這種情況可能會並行發生多次! X線程(我忘了提及),getSharedObject被生成並存儲在單例的hashmap變量中。所以每一組線程都可以訪問自己的對象。這就是爲什麼我試圖使用鎖,並將它作爲LOCK的自我getSharedObject!如果我使用靜態我將不得不爲每個getSharedObject – kenny 2011-12-19 05:07:42

+0

創建新的變量那麼,我不知道你的應用程序如何工作。我相信你可以適應你的情況!整個想法是,在恢復之前必須等待彼此的線程必須共享一個CyclicBarrier。一定要正確發佈障礙! (也就是說,由於您將有許多CyclicBarriers,因此最好使用併發集合來保存實例,例如ConcurrentHashMap)。 – 2011-12-19 12:12:40

0

這是一種典型的多線程情況,稱爲Rendez-Vous(法語單詞意思是「約會」)。基本上你的N線程將有一個約會,應該都在等待一個點,直到所有人達到它。正如@布魯諾所說的,您可以使用CyclicBarrier對象來管理這種情況。如果你的場景只運行一次,那麼你也可以使用CountDownLatch

這裏是你如何能做到這一點:

static final CountDownLatch rendezVousPoint = new CountDownLacth(numberOfThreads); 

//Every thread does the following right before waiting on the rendez vous point 
rendezVousPoint.countDown(); 
rendezVousPoint.await(); 

在這種情況下,每個線程將在await()方法阻止,直到最後一個線程到達並釋放所有的人(rendezVousPoint數爲0)

+0

我不確定我喜歡這個(ab)使用'CountDownLatch'。你正在顛覆一個'CountDownLatch',使其行爲完全像一個'CyclicBarrier'(它已經被構建來處理這種情況)。像你這樣調用的方法'CDL.countDown()'和'CDL.await()',其行爲大體上類似於'CB.await()',但是它們有2種方法用於某種目的(這不是被稱爲一個權利之後):通常,工作線程會調用CDL.countDown(),只有一個主線程會調用CDL.await(),才能阻塞,直到所有工作線程完成任務。 – 2011-12-18 23:56:58

+0

@BrunoReis感謝您的評論,我傾向於對此表示不同意。按照官方的java文檔,一個接一個地執行'CDL.countDown()'和'CDL.await()'沒有任何問題。一個'CyclicBarrier'(根據文檔)是一個'CountDownLatch'的可重用(可以設置和重置幾次)版本, – GETah 2011-12-19 14:56:39