2010-07-02 96 views
2

問題是:類C控制類B是否讓B再次將A添加到queueOfA,但是我怎樣才能確保當A通知C,並在B的queueOfA變空之前立即更新,因爲B類運行速度非常快,可能會刪除所有A,因此在C更新之前變爲空queueOfA,這可能會導致C的run方法結束。java線程同步問題,如何實現可觀察線程

請幫我一把!

class A extends Observable implements Runnable{ 
    //... 
    void run(){ 
    //... 
    if (goBackToTheQueueAgain == true){ 
     setChanged(); 
     notifyObservers();//notify C that to let B add itself back 
    } 
    //... 
} 

class B extends implements Runnable{ 
    Queue<A> queueOfA;// initialy, queueOfA contains several A's 
    //... 
    void run(){ 
     //... 
     A retrieved = queueOFA.remove(); 
     Thread aThread = new Thread(retrieved); 
     aThread.start(); 
     //... 
    } 
} 

class C implements Observer, Runnable { 
    B b; //initially class C contains an instance of B 
    //... 
    void update(Observable o, Object arg){ 
     if(o instanceof A){ 
     A a = (A) o; 
     b.queueOfA.add(a); 
     } 
    } 
    //... 
    void run(){ 
     //... 
     Thread bThread = new Thread(b); 
     bThread.start(); 
     while (b.queueOfA.isEmpty() == false){ 
      // if queueOfA is not empty loop for ever 
     } 
     //.. 
    } 
} 
+0

哇,這是一些句子!我想你說,呃,一口氣! – mdma 2010-07-02 18:58:19

+0

深呼吸:) – 2010-07-02 19:01:51

+0

我有一個可怕的英語表達風格。 – Rn2dy 2010-07-02 19:24:27

回答

5

的問題不在於你必須儘快通知更新 - 你不能保證。例如,考慮你在隊列中只有一個元素開始。這將從隊列中移除,然後隊列爲空,但該元素仍在處理中。 A線程可以採取它喜歡的時間 - 即使隊列爲空,C也不應該終止。

修復方法是C應該等到所有A都完全處理完畢。也就是說,A的運行方法已經結束,而不會將A重新放回隊列。這可以使用倒計時鎖存器來完成。最初將鎖存器設置爲隊列的大小(A的數量),並在每次A完全處理時減少該鎖存器。只有當該鎖存器變爲零時C纔會退出。

C相類似這樣

CountdownLatch latch; 

void run(){ 
    //... 
    this.latch = new CountDownLatch(queueOfA.size()); 
    Thread bThread = new Thread(b); 
    bThread.start(); 
    latch.await(); 
    //.. catch InterruptedException etc.. 
} 

void notifyDone(A a) { 
    this.latch.countDown(); 
} 

和A的run方法是

void run(){ 
    //... 
    C c = ...; // passed in from somewhere 
    if (goBackToTheQueueAgain == true){ 
     setChanged(); 
     notifyObservers();//notify C that to let B add itself back 
    } 
    else 
     c.notifyDone(this); 
} 

A需要到C的引用,以便它可以直接在它完成通知。

就我個人而言,我不會在這裏使用Observer/Observable,因爲您的通知具有特定含義 - 該項目可以重新排序。觀察者模式最適合通知狀態的變化,狀態可以從被觀察的實例中獲得。這不是這種情況,並且從這種抽象的解耦中沒有真正的收益。如果你想保持抽象而不是將A耦合到C,你可以引入一個額外的接口,例如

interface QueueHandler<T> 
{ 
    void requeue(T t); 
    void completed(T t); 
} 

並在C上實現它,並將它傳遞給每個A而不是當前的Observer接口。但同樣,A類和C類緊密耦合,所以你也可以將C傳遞給A並讓它直接通知。

+0

閂鎖的東西是好的,但問題仍然是B快速刪除queueOfA中的所有元素,所以B快速完成,但鎖存器從不倒計數到零,因爲A不再通知C!所以我們真的需要讓A完成更新然後讓B執行remove然後... – Rn2dy 2010-07-02 21:55:43

+0

問題是:B最初設置爲運行一個固定時間,在執行過程中如果B變空,則B將立即停止執行,但由於A有可能再次返回隊列,所以A必須確保C讓A在B發現自己是空的之前回到隊列中! 請幫我一把。 Mr.mdma – Rn2dy 2010-07-02 22:08:54

+0

我不明白爲什麼A不通知C - 它是A的運行方法的一部分。你可以讓B使用BlockingQueue.take(),直到一個元素可用 - B永遠不會退出 - 循環是無條件的。當C發現鎖存器爲0時(在latch.await()之後)它可以中斷B,使得B跳出循環。 – mdma 2010-07-02 22:16:22