【问题标题】:Condition give the effect of having multiple wait-sets per object?条件会产生每个对象有多个等待集的效果吗?
【发布时间】:2013-08-31 16:30:51
【问题描述】:

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

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

有人可以解释一下吗?

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

【问题讨论】:

  • This 应该会有所帮助。

标签: java multithreading conditional-statements reentrantlock


【解决方案1】:

一个锁可以与多个条件相关联。锁是一个“对象”,每个条件都是一个“等待集”。这允许独立条件共享临界区。例如,考虑有界生产者-消费者问题。解决它的一种方法是拥有一个保护队列的锁和两个独立的等待集:一个用于生产者,等待槽将项目放入队列,另一个用于等待项目获取的消费者。使用普通的旧 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 条件)。这两个条件都与同一个临界区(锁定)相关联,因此我们保持了通常的排除和等待时释放锁的保证,同时获得了分离等待队列的能力。

【讨论】:

  • 消费者的“while”处缺少一个“)” :)
  • 谢谢,我们可以不使用额外的 2 个不同的对象(与同步块中使用的锁定对象不同)模拟相同的事情,以使用 wait 和 notify 实质上复制 Conditional 对象吗?它会工作还是等待和通知独立于调用它们的对象?
  • @mss 由于wait()synchronized 的交互方式,我不确定这是否可以正常工作。当我们进入synchronized(lock) 部分时,我们拥有lock 的监视器的所有权。在调用lock.wait() 时,我们释放此所有权,以便其他线程可以进入synchronized(lock) 部分并做一些工作。如果我们不调用lock.wait() 而是调用someOtherObj.wait(),我们保留lock 的监视器的所有权,并且没有其他线程可以继续。这就是 Lock and Conditions 的诀窍——只有一个“监视器”(与 Lock 相关联),所以不会出现这个问题。
【解决方案2】:

在显式锁之前,我们使用 Object wait()notify() 方法使线程等待某些事件发生,然后使用 notify() 触发它们,并且该对象的互斥锁必须与调用这些方法的线程一起使用.

所以每个锁对象只有一个等待集。等待集是存储在对象上调用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 为 NOT EMPTY 的条件,而生产者线程将等待条件 NOT FULL。

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2015-05-10
      • 1970-01-01
      • 2016-09-01
      • 2017-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多