条件是否为每个对象提供多个等待集?
我正在阅读java.util.concurrent.locks.Condition
Condition。
条件因素将对象监视器方法(wait,notify和notifyAll)>分解为不同的对象,以通过将它们与使用任意Lock实现相结合来实现每个对象具有多个等待集的效果。
有人可以解释一下吗?
这比普通的同步块或方法有什么好处?
一个锁可以与许多条件相关联。 锁是一个“对象”,每个条件都是“等待集”。 这允许共享关键部分的独立条件。 例如,考虑有限的生产者 – 消费者问题。 解决这个问题的一种方法是拥有一个保护队列的锁,以及两个独立的等待集:一个用于生产者,等待插槽将项放入队列,另一个用于等待物品采取的消费者。 使用普通的旧synchronized
和wait/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上等待。