[英]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語句,但是這很容易受到虛假喚醒的影響。
您可以使用CountDownLatch
或CyclicBarrier
。
使用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.