您想使用计数信号量。条件变量用于在监视器内调度线程。这不是你想要做的。
您创建一个计数信号量并将计数设置为零
// create a counting semaphore with an initial count of zero
java.util.concurrent.Semaphore s = new java.util.concurrent.Semaphore(0);
您将信号量传递给您的班级进行处理。完成后,它通过调用将计数增加到 1 s.release()
。
要在处理器完成之前阻塞线程,请调用s.aquire()
. 该调用将导致您的其他线程阻塞,直到处理器调用s.release()
.
这是最简单的解决方案。
顺便说一句,s.aquire()
并且s.release()
是线程安全的,因此您不需要使用 synchronize 关键字。线程可以共享对信号量的引用并在不锁定的情况下调用其方法。
更新:
我将在这里回复您的评论,而不是发表新评论。
是的,在您的情况下,wait()/notify() 解决方案类似于使用信号量。用信号量重写 rsp 的解决方案,它看起来像:
java.util.concurrent.Semaphore s = new java.util.concurrent.Semaphore(0);
public setDone() {
s.release();
}
public waitUntilDone() {
s.aquire();
}
它更简单,您不需要不必要的锁(注意我从方法 decs 中删除了 synchronized 关键字。)。
条件变量(wait()/notify())和信号量之间有两个区别。
区别 #1:对 notify() 的调用可能会丢失,对 release() 的调用永远不会丢失
第一个区别是,如果没有线程通过调用 wait() 等待,则调用 notify() 将丢失。解决方法是在调用 wait() 之前检查条件。基本上,我们需要记住 notify() 是使用共享变量调用的,因此我们不会在 worker 调用 notify() 后意外调用 wait(),否则我们会死锁。无论调用acquire() 和release() 的顺序如何,计数信号量都有效,因为它们在内部维护一个计数。
区别#2:调用wait()会自动释放锁,调用acquire()不会
一些背景信息将在这里有所帮助。在您的程序中,boolean done = false;
变量是条件,但不是条件变量。令人困惑的术语,我知道。条件变量是具有操作 wait() 和 notify() 的变量。Java 中的每个对象都有一个隐藏在内部的条件变量和一个相应的锁。
所有条件变量都与锁相关联。在调用 wait() 和 notify() 之前,您必须获取锁(如果不这样做,您将得到运行时异常,请尝试一下)。一旦获得锁,调用 wait() 会自动释放锁,允许监视器内的另一个线程可能调用 notify()。有时,这正是您想要的,尝试用信号量模拟这种行为会复杂得多。
注意:我使用的是监视器的学术定义,它与监视器的 Java 定义完全不同。