【问题标题】:How can I wake/suspend a particular (Group of) Thread(s) with notify/wait()?如何使用 notify/wait() 唤醒/暂停特定(组)线程?
【发布时间】:2017-04-06 12:08:54
【问题描述】:

我想知道例如 r.wait() 是否有效?使用此代码:

public class Buffer1<T> {
private T content;
private boolean empty;
private Object r = new Object();
private Object w = new Object();

public Buffer1() {
empty = true;    }

public Buffer1(T content) {
this.content = content;
empty = false;    }

public T take() throws InterruptedException {
synchronized (r) {
while (empty) {
r.wait();
}

synchronized (w) {
empty = true;
w.notify();
return content;
  }
 }
}

public void put(T o) throws InterruptedException {
synchronized(w) {
while (!empty) {
w.wait();
}

synchronized (r) {
empty = false;
r.notify();
content = o;
}

r.wait()、w.wait()、r.notify()、w.notify() 是如何工作的?以及它们如何与 synchronized(r) / synchronized(w) 一起工作?

【问题讨论】:

  • 好吧,notifyAll() 可能会让你的生活更简单……它实际上不应该唤醒特定的线程组。它唤醒所有线程。这就是为什么wait() 总是应该出现在循环中的原因。一旦被唤醒,线程本身应该检查现在是否是唤醒的好时机,如果不是,则返回wait()ing。但是 wake 和 notify 是并发编程的低级结构,你真的应该考虑使用 Executor Framework 来简化并发模块的组合。
  • 或者java.util.concurrent包中的信号量。

标签: java multithreading wait notify synchronized-block


【解决方案1】:

线程不会分组挂起。发生的情况是一个线程进入一个同步块或方法,获取锁(这里是 r 或 w),如果线程调用它获取锁的对象上的等待,那么线程被挂起,释放它调用的锁,并且被添加到该锁的等待集中。

这里有一个模式,其中有一个围绕调用等待的循环。调用该方法的线程必须一直等待,直到循环中的测试为假。让线程继续等待的状态称为条件。循环调用wait方法主要是因为被通知的线程没有锁的所有权,需要在重新获取锁后检测当前状态。

您可以通过在该锁上调用 notifyAll 来唤醒该锁的等待集中的所有线程。在实践中,这并不是最优的,因为通常只有一个线程可以获取锁并一次取得进展。当争夺同一个锁的线程可能正在等待不同的条件并且通知可能是与某些线程无关的状态时,就会使用 notifyAll。如果使用了 notify,那么只有一个线程(调度程序随心所欲地选择)被唤醒。如果线程等待的条件不是通知的条件,则通知丢失并且没有线程取得进展。使用 notifyAll 如果通知适用于任何线程,则其中一个线程可以取得进展。这优于替代方案,即使以所有其他等待线程进行上下文切换并返回等待为代价。

在发布的代码中,目的似乎是通过为每个条件设置一个单独的锁定对象来避免使用 notifyAll。对象 r 有线程等待它直到缓冲区不为空,对象 w 有线程等待它直到缓冲区为空。这样,当调用 notify 时,肯定会唤醒与 notify 相关的线程(只有等待 put 的线程才能被 w.notify() 唤醒)。

此代码的问题在于 put 和 take 操作同时获取了两个锁,并且它们以彼此相反的顺序获取它们。这是造成僵局的好方法。使用同步关键字和内在锁,没有办法超时和退出,也没有恢复的好方法。一旦你遇到一个线程有 r 并且想要 w,而另一个线程有 w 并且想要 r 的情况,那么你就被卡住了。各自持有一个锁的两个线程无法继续进行,任何其他线程都无法获得任何一个锁,导致每个尝试进入该缓冲区的方法的线程都阻塞,直到您杀死 JVM。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多