[英]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.