在重入锁中等待条件

2022-09-01 10:55:47

以下代码取自条件的 JavaDoc

class BoundedBuffer {
  final Lock lock = new ReentrantLock();
  final Condition notFull  = lock.newCondition(); 
  final Condition notEmpty = lock.newCondition(); 

  final Object[] items = new Object[100];
  int putptr, takeptr, count;

  public void put(Object x) throws InterruptedException {
    lock.lock();
    try {
      while (count == items.length) 
        notFull.await();
      items[putptr] = x; 
      if (++putptr == items.length) putptr = 0;
      ++count;
      notEmpty.signal();
    } finally {
      lock.unlock();
    }
  }

  public Object take() throws InterruptedException {
    lock.lock();
    try {
      while (count == 0) 
        notEmpty.await();
      Object x = items[takeptr]; 
      if (++takeptr == items.length) takeptr = 0;
      --count;
      notFull.signal();
      return x;
    } finally {
      lock.unlock();
    }
  } 
}

想象一下 2 个线程,使用者生产者,一个使用 ,一个在 的单个实例上。takeputBoundedBuffer

假设 Consumer 先去,在其中他锁定并循环运行。take()locknotEmpty.await();

现在生产者怎么可能进入锁定的方法,这已经被消费者持有了?put()lock

我在这里错过了什么?线程是否在等待其条件之一时“暂时释放”?锁的重入究竟意味着什么?lock


答案 1

两者都允许一个线程在等待时放弃锁,而另一个线程可以获得锁。要停止等待,线程必须重新获取锁。Locksynchronized

注意:它们不会完全释放它,如果您进行堆栈跟踪,则可以有多个线程似乎同时持有锁定,但最多其中一个线程将运行(其余线程将被阻塞)

From Condition.await()

与此条件关联的锁以原子方式释放,并且当前线程因线程调度目的而被禁用并处于休眠状态,直到发生以下四种情况之一:

  • 其他一些线程调用此条件的signal()方法,并且当前线程恰好被选为要唤醒的线程;或
  • 其他一些线程调用此条件的 signalAll() 方法;或
  • 其他一些线程中断当前线程,并且支持中断线程悬架;或
  • 发生“虚假唤醒”。

在所有情况下,在此方法返回之前,当前线程必须重新获取与此条件关联的锁。当线程返回时,保证保持此锁


答案 2

就重新绑定而言,这意味着持有某个锁的线程可以再次重新获取相同的锁。如果不是这样,则方法将无法调用同一对象的另一个方法。synchronizedsynchronized

重新融入不涉及对你的问题的理解。


推荐