查看 javadoc 中
Condition
的示例注释。 来源
假设这种情况:
时间轴:
在 t0,Thread-1 在第 24 行获取锁
在t1,由于count==0进入L27忙等待 根据 javadoc 此时,线程释放锁并进入休眠状态。
在 t2 时,Thread-2 获取第 10 行 put 中的锁
在 t3 处,线程执行到第 17 行,这向 Thread-1 发出信号
由于 Thread-2 从未达到释放其锁的程度(第 19 行),因此在时间 t3 时发生了什么,Thread-1 可以执行吗?这会破坏一次只允许一个线程执行 ReentrantLock 的约定吗?
1 class BoundedBuffer<E> {
2 final Lock lock = new ReentrantLock();
3 final Condition notFull = lock. newCondition();
4 final Condition notEmpty = lock. newCondition();
5
6 final Object[] items = new Object[100];
7 int putptr, takeptr, count;
8
9 public void put(E x) throws InterruptedException {
10 lock. lock();
11 try {
12 while (count == items. length)
13 notFull. await();
14 items[putptr] = x;
15 if (++putptr == items. length) putptr = 0;
16 ++count;
17 notEmpty. signal();
18 } finally {
19 lock. unlock();
20 }
21 }
22
23 public E take() throws InterruptedException {
24 lock. lock();
25 try {
26 while (count == 0)
27 notEmpty. await();
28 E x = (E) items[takeptr];
29 if (++takeptr == items. length) takeptr = 0;
30 --count;
31 notFull. signal();
32 return x;
33 } finally {
34 lock. unlock();
35 }
36 }
37 }
不,当在 ReentrantLock
上阻塞的线程收到信号时,不会违反
await()
的互斥保证。这样的线程在重新获取锁之前无法从 await()
返回,而在任何给定时间只有一个线程可以持有该锁。换句话说,有信号线程最早可以从 await()
返回,就在调用 signal()
的线程释放锁之后。
条件#signal()导致当前线程等待,直到收到信号或中断。
与此
关联的锁被原子释放,当前线程出于线程调度目的而被禁用,并处于休眠状态,直到发生以下四种情况之一: 其他线程调用了该Condition
在此方法可以返回之前,当前线程必须重新获取与此条件相关的锁
signal()
- 的
方法,并且当前线程恰好被选为要唤醒的线程;或其他一些线程为此Condition
signalAll()
- 调用
方法;或其他线程中断当前线程,支持线程挂起中断;或Condition
- 发生“
虚假唤醒- ”。
在所有情况下,[强调]。当线程返回时,保证持有这个锁。
[...]
如果有任何线程在此条件下等待,则选择一个线程进行唤醒。该线程
必须重新获取锁,然后才能从
await
[强调已添加]。 [...]