在Condition接口的文档中: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html
有一个使用条件的示例类。我将在这里复制/粘贴:
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();
}
}
}
我不明白这是如何工作的(注意:我没有测试它,我只是假设它有效)而不会造成死锁?
如果我将BoundedBuffer.put调用一百次,那么在第一百次调用它将在notFull.await()方法中被阻塞,这将处于锁定状态。 如果我然后从另一个线程做BoundedBuffer.take(),那么我应该在lock.lock()的第一行被阻止。
我在这里错过了什么吗?
答案 0 :(得分:2)
是的,你确实错过了什么。来自JavaDoc:
等待条件提供的关键属性是它以原子方式释放关联的锁并挂起当前线程,就像Object.wait一样。
因此,在调用await()
时会释放锁定。
来自await()
方法本身的JavaDoc:
void await()抛出InterruptedException
使当前线程等待,直到发出信号或中断为止。与此条件关联的锁被原子释放,并且当前线程因线程调度而被禁用,并处于休眠状态,直到发生以下四种情况之一:
方法signal()
唤醒一个线程,该线程将在继续之前重新获取锁。来自方法signal()
的JavaDoc:
void signal()
唤醒一个等待线程。如果任何线程正在等待这种情况,则选择一个线程进行唤醒。然后该线程必须在从await返回之前重新获取锁。