1

我想知道例如 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() 是如何工作的?它们如何与同步(r)/同步(w)一起工作?

4

1 回答 1

0

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

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

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

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

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

于 2017-01-10T05:06:51.703 回答