我假设顶部的类是 Q,它缺少一些代码。无论如何,总体思路是布尔值valueSet
和wait()
/notify()
呼叫协同工作。
如果消费者已经开始等待,那么他已经通过synchronized获得了Q实例的锁get()
方法,然后在等待时释放它。
如果消费者尚未开始等待,则生产者可能拥有 Q 实例的锁,因为put()
方法在同一个锁上同步。一旦生产者退出锁,他就会调用notify()
以及将 valueSet 布尔值设置为 true.
消费者的下一个电话get()
将读取布尔值在尝试等待之前,注意到那里有东西,取出其中的内容n
并做任何需要做的工作。如果该值尚未设置,这意味着在消费者缺席的情况下什么也没有进来,他会wait()
锁定新工作和下一个工作notify()
会叫醒他的。
Update
在评论中的场景中,您本质上是在询问完全相同的情况,但方向相反。同样的逻辑也适用。
消费者当前正在等待,生产者调用notify()
。生产者当前拥有锁,并将在该方法的持续时间内继续持有锁。全部notify()
所做的就是让当前正在等待锁的另一个线程知道,当锁被释放时,它可以尝试获取锁并恢复执行。在这种情况下,只有一个其他线程,但如果有多个线程,那么它只会选择一个(唤醒每个人,notifyAll()
应该调用)。
- 生产者退出该方法,释放锁。
- 消费者醒来并获取锁。
此时,生产者是否已经恢复并当前正在等待锁,或者是否尚未进入该方法,这是不明确的。布尔标志和相同的串联wait()
/notify()
也适用于此。
在消费者通过退出方法释放锁之前,它会将布尔标志设置为 false 并调用notify()
.
如果生产者当前已经在等待锁,则调用notify()
会让它知道当锁被释放时它可以唤醒并继续。
如果生产者没有等待wait()
调用,它必须在方法外部(可能等待进入方法并以这种方式获取锁)。当消费者退出该方法并释放锁时,生产者获取它并检查布尔标志。它被设置为 false,因此生产者不尝试打电话 wait()
然后将其值去掉,设置布尔标志并调用notify()
.