为什么不能等待并直接在ReentrantLock的对象上调用信号方法.为什么需要条件? [英] Why can't await and signal methods be called directly on object of ReentrantLock. Why do I need Condition?

查看:51
本文介绍了为什么不能等待并直接在ReentrantLock的对象上调用信号方法.为什么需要条件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在旧的同步块中,我们使用相同的对象进行同步,还使用了 wait notify 方法.所以他们都可以引用同一个锁.有道理.

In old synchronized block, we used same object to synchronize on, also used wait and notify methods. So they can all refer to same lock. Makes sense.

因此,当我使用ReentrantLock类时,为什么不能同时使用相同的变量来调用 lock unlock 以及 await 信号?为什么我需要使其他Condition变量变?

So when I use class ReentrantLock, why can't I also use same variable to call lock, unlock as well as await and signal? Why do I need to make additional Condition variable?

这就是为什么我需要这样做:

That is, why I need to do this:

Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    void doSomething() {
        lock.lock();
            //some code
            condition.await();
            //some code
        lock.unlock();
    }

代替这个:(这种编码是否更逻辑)?

Instead of this: (wouldn't this type of coding be more logic)?

Lock lock = new ReentrantLock();

    void doSomething() {
        lock.lock();
            //some code
            lock.await();
            //some code
        lock.unlock();
    }

来自文档:条件实例本质上绑定到锁.为什么要这样设计?为什么不只有一个Lock类型的变量具有等待和信号方法呢?

from docs: A Condition instance is intrinsically bound to a lock. Why design it that way? Why not just have one variable of type Lock which would have await and signal method?

推荐答案

Lock Condition 的分隔允许您拥有多个 Condition Lock 的code>,由

The separation of Lock and Condition allows you to have more than one Condition per Lock, which is documented by Condition:

条件排除了 Object 监视方法( wait notify notifyAll )分成不同的对象,通过结合使用任意 Lock 来实现每个对象具有多个等待集的效果 [加重] code>实现.

Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object [emphasis added], by combining them with the use of arbitrary Lock implementations.

[ Lock 实现]允许更灵活的结构,可能具有完全不同的属性,并且可能支持多个关联的 Condition 对象 [.

[Lock implementations] allow more flexible structuring, may have quite different properties, and may support multiple associated Condition objects [emphasis added].

借助该功能,您可以执行以下操作:

With that ability you can do things like:

import java.util.Objects;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Stack<E> {

  private final Lock lock = new ReentrantLock();
  private final Condition notEmpty = lock.newCondition();
  private final Condition notFull = lock.newCondition();

  private final Object[] elements;
  private int size;

  public Stack(int capacity) {
    elements = new Object[capacity];
  }

  public E pop() throws InterruptedException {
    lock.lockInterruptibly();
    try {
      while (size == 0) {
        notEmpty.await();
      }
      @SuppressWarnings("unchecked")
      E element = (E) elements[--size];
      elements[size] = null;
      notFull.signal();
      return element;
    } finally {
      lock.unlock();
    }
  }

  public void push(E element) throws InterruptedException {
    Objects.requireNonNull(element);
    lock.lockInterruptibly();
    try {
      while (size == elements.length) {
        notFull.await();
      }
      elements[size++] = element;
      notEmpty.signal();
    } finally {
      lock.unlock();
    }
  }
}

这种方法有两个好处:

  1. 当推入一个元素时,仅发出等待弹出一个元素的线程的信号,反之亦然.换句话说,只有等待特定 Condition 的线程才会发出信号.
  2. 您不必调用 signalAll(),这意味着只有一个线程被唤醒.
  3. (奖金),至少在我看来,提高了代码的可读性.
  1. When an element is pushed only a thread waiting to pop an element is signaled and vice versa. In other words, only the thread(s) waiting on a specific Condition are signaled.
  2. You don't have to invoke signalAll(), meaning only one thread is woken up.
  3. (Bonus) Improves readability of code, at least in my opinion.


这里是相同的 Stack 类,但使用的是 synchronized :

import java.util.Objects;

public class Stack<E> {

  private final Object lock = new Object();

  private final Object[] elements;
  private int size;

  public Stack(int capacity) {
    elements = new Object[capacity];
  }

  public E pop() throws InterruptedException {
    synchronized (lock) {
      while (size == 0) {
        lock.wait();
      }
      @SuppressWarnings("unchecked")
      E element = (E) elements[--size];
      elements[size] = null;
      lock.notifyAll();
      return element;
    }
  }

  public void push(E element) throws InterruptedException {
    Objects.requireNonNull(element);
    synchronized (lock) {
      while (size == elements.length) {
        lock.wait();
      }
      elements[size++] = element;
      lock.notifyAll();
    }
  }
}

现在注意,每个线程都必须等待相同的条件".并在发生任何事情时通知每个等待线程.您必须通知所有等待中的线程,因为您无法更好地控制通知哪些线程.

Notice now that every thread has to wait on the same "condition" and that every waiting thread is notified any time anything happens. You have to notify all waiting threads because you have no finer control over which thread(s) are notified.

这篇关于为什么不能等待并直接在ReentrantLock的对象上调用信号方法.为什么需要条件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆