条件是否为每个对象提供多个等待集?

我正在阅读java.util.concurrent.locks.Condition Condition。

条件因素将对象监视器方法(wait,notify和notifyAll)>分解为不同的对象,以通过将它们与使用任意Lock实现相结合来实现每个对象具有多个等待集的效果。

有人可以解释一下吗?

这比普通的同步块或方法有什么好处?

一个锁可以与许多条件相关联。 锁是一个“对象”,每个条件都是“等待集”。 这允许共享关键部分的独立条件。 例如,考虑有限的生产者 – 消费者问题。 解决这个问题的一种方法是拥有一个保护队列的锁,以及两个独立的等待集:一个用于生产者,等待插槽将项放入队列,另一个用于等待物品采取的消费者。 使用普通的旧synchronizedwait/notify API,我们能做的最好的就是这些:

  • 制片人:

     synchronized (lock) { while (queue.isFull()) { lock.wait(); } queue.put(sth); lock.notify(); } 
  • 消费者:

     synchronized (lock) { while (queue.isEmpty() { lock.wait(); } product = queue.take(); lock.notify(); } 

这样做的缺点是,在队列的每次更改都会唤醒生产者和消费者,即使它不可能允许给定的线程继续进行(例如,当其他一些消费者从队列中获取项目时,消费者会被唤醒)。 使用Lock / Condition API,我们可以实现将等待的消费者和生产者分开的解决方案,从而减少冗余唤醒和检查:

 Lock lock = new ReentrantLock(); Condition hasPlace = lock.newCondition(); Condition hasItems = lock.newCondition(); 
  • 制片人:

     lock.lock(); try { while (queue.isFull()) { hasPlace.await(); } queue.put(sth); hasItems.signal(); } finally { lock.unlock(); } 
  • 消费者:

     lock.lock(); try { while (queue.isEmpty()) { hasItems.await(); } product = queue.take(); hasPlace.signal(); } finally { lock.unlock(); } 

这样,消费者等待生产者生成一些项目(hasItems条件),并且在从队列中移除项目时,它通知生产者存在空槽(hasPlace条件)。 这两个条件都与相同的关键部分(Lock)相关联,因此我们保持通常的排除和释放锁定等待保证,同时获得分离等待队列的能力。

例如,对于有界数据结构,您可以使用条件“notEmpty”和“notFull”并等待它们。 只是一个例子。 看看这里的例子。

在Explicit Locks之前,我们使用Object wait()notify()方法使线程等到某个事件发生,然后使用notify()触发它们,并且该Object的互斥锁必须与调用这些方法的线程一起使用。

所以每个锁对象只有一个等待集。 Wait set是存储在对象上调用wait()的线程的集合(不是升级)。

但是使用单个锁的Explicit Lock框架,您可以为与同一个锁相关的不同条件创建多个等待集。 正如Javadoc中的例子也解释了同样的事实。

 Multiple Conditions == Multiple Wait sets final Lock lock = new ReentrantLock(); //Single Lock final Condition notFull = lock.newCondition(); //Multiple conditions final Condition notEmpty = lock.newCondition(); 

因此,在来自JavaDoc的Buffer示例的情况下,消费者线程将等待Buffer的状态为非EMPTY,并且生产者线程将在条件NOT FULL上等待。