簡體   English   中英

如何喚醒等待相同條件的所有線程?

[英]How to wake up all threads waiting on same condition?

我有以下情況。 幾個線程正在等待相同的條件。 當得到通知時,所有應該停止等待,更改標志並返回對象:

 public Object getObject(){
    lock.lock();
    try {
        while (check)){
            condition.await();
        }

        return returnObjectAndSetCheckToFalse();
    } finally {
        lock.unlock();
    }
}

但是這段代碼不起作用,因為更快的線程可能會將check標志更改為false,而第二個更慢的線程將再次阻塞。 可能有一個邏輯,即兩個等待線程都將被喚醒,它們都將check flag設置為false,並返回對象? 或許它是矛盾的?

最簡單的方法是將wait更改為if語句,但是這很容易受到虛假喚醒的影響。

您可以使用CountDownLatchCyclicBarrier

使用Future也是一種可能性, FutureTask更具體。 它有一個方法get() ,可用於阻止代碼執行,直到Future完成其工作,從而滿足您的要求。

您還可以實現自己的Barrier,它會在循環中執行wait()直到滿足某個條件。 實現該條件會觸發notifyAll() ,循環將完成,所有線程都可以繼續。 但這將重新發明輪子。

我認為你正在努力實現,使用Future s:

ExecutorService executor = Executors.newCachedThreadPool();

// producer
final Future<String> producer = executor.submit(new Callable<String>() {
    @Override
    public String call() throws Exception {
        Thread.sleep(5000);
        return "done";
    }
});

// consumers
for (int i = 0; i < 3; i++) {
    final int _i = i;
    executor.submit(new Runnable() {
        @Override
        public void run() {
            System.out.println("Consumer "+_i+" starts.");
            try {
                String value = producer.get();
                System.out.println("Consumer "+_i+" ends: "+value);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

如果你運行它,你應該看到所有的消費者線程打印出他們的開始消息,然后暫停,然后消費者線程打印出他們已經完成。 顯然你必須將產生getObject()值的任何東西改成Callable但我敢打賭這會簡化代碼,因為現在它將在程序上進行結構化,而不是將計算結果存儲在共享中變量。 我也比使用手動鎖定的任何代碼更自信它的線程安全。

一種方法是使用wait()而不是condition.await() 然后使用notifyAll()喚醒線程。

理想情況下,您將繼續使用導致線程休眠的條件對象,並調用方法signalAll()來喚醒所有線程。

在你的代碼我只會添加:

public Object getObject(){
lock.lock();
try {
    while (check)){
        condition.await();
    }
        condition.signalAll();
    return returnObjectAndSetCheckToFalse();
} finally {
    lock.unlock();
}

}

我甚至會考慮在returnObjectAndSetCheckToFalse()方法中而不是在return語句之前使用condition.signalAll()的可能性。

據我所知,如果你的condition.await()返回,你需要從所有線程中的方法體返回。 這個丑陋的解決方案應該有所幫助,盡管我認為有更好的解決方法:

public Object getObject() {
  lock.lock();
  try {
    int localstate = this.state;

    while (check && localstate == this.state)) {
      condition.await(); // all threads that are waiting here have the same state
    }

    if (!check) {
      this.state++; // first thread will change state thus making other threads ignore the 'check' value
    }

    return returnObjectAndSetCheckToFalse();
  } finally {
    lock.unlock();
  }
}

確實這是矛盾的。 你想要實現的是有問題的。 你希望在條件上等待的線程應該得到結果並繼續,但是一個在通知之后不會調用getObject的線程。 至少,這是不公平的。 該線程是否設法在通知之前調用getObject ,是純隨機的。 你應該減少不確定性,而不是增加它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM