A线程在使用Lock获得锁的后,可能会由于某些条件不满足,而不能继续执行,需要等待条件满足时,可以使用 Condition,Lock接口有一个newCondition()方法实化Condition,调用 Condition.await()当前线程释放锁,进入阻塞状态,当B线程获得这个锁并使条件满足时,调用同一个Condition实例的notify或notifyAll方法时,A线程被唤醒,但并未执行,需要B线程释放锁之后,A线程能够得到锁,才从await之后的代码执行。
A线程调用Condition.await()方法之后,
如果A线程在进入await方法之前被中断,await立即返回,抛出InterruptedException
,
否则进入阻塞状态,A线程被唤醒的条件:
1.同一个Condition实例的notifyAll被调用
2.同一个Condition实例的notify被调用,碰巧将A线程选为被唤醒的线程
4.有可能产生”虚假唤醒“
由于A线程可能是被”虚假唤醒“的,则此await方需在一个循环块中检测条件是否满足。
A线程被唤醒后,需要获得Lock才能执行后续程序, 未能获得LOCK则继续阻塞。
如果A线程阻塞过程中,被其它线程中断,那么唤醒并获得锁后,await方法抛出InterruptedException
,
如果A线程被唤醒之后,获得锁之前,被其它线程中断,则调用设标中断标志,Thread.currentThread().interrupt();
方法:
void |
有可能被“虚假唤醒" 需要在循环中使用 |
boolean |
有可能被“虚假唤醒" 需要在循环中使用 |
long |
|
void | awaitUninterruptibly() 造成当前线程在接到信号之前一直处于等待状态。 |
boolean | awaitUntil(Date deadline) 造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。 |
void | signal() 唤醒一个等待线程。 |
void | signalAll() 唤醒所有等待线程。 |
java API中给出的示例:
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();
}
}
}
源码分析:
await方法:
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();//刚进入方法时如果有中断,抛出异常
Node node = addConditionWaiter();//新生成一个等待节点
int savedState = fullyRelease(node);//释放多层锁
int interruptMode = 0;
while (!isOnSyncQueue(node)) {//此节点未在同步节点队列中,isOnSyncQueue会返回假,直至signal被调用时才加入到队列中跳出循环
LockSupport.park(this);//线程阻塞,线程可能被”虚假唤醒“因此需要循环
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;//线程被唤醒后,监测线程中断标志, 发生中断则把node存入同步节点队列 ,跳出循环
}
//将节点存入同步节点队列目的是按队列顺序获得锁
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)//acquireQueued方法内存是个死循环,直至获得锁才返回,未获得锁就继续阻塞
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);//发生中断抛出异常或设置中断标志
}