一、介绍
condition
接口提供了类似Object的监视器的方法,用来实现等待通知模式。但是与Object监视器又有一定的区别,与不同。主要体现在;
- 等待队列
- Obejct模式 :一个
- Condition:多个
- 等待超时模式
- Object模式:不支持
- Condition模式:支持
二、使用方法
// 声明锁的对象
ReentrantLock lock = new ReentrantLock();
// 获取监视器
Condition condition = lock.newCondition();
// 获取锁
lock.lock();
// 等待
condition.await();
//通知
condition.signal();
//释放锁
lock.unlock();
当调用await()
方法之后,当前线程会释放锁并在此等待,其他线程调用Condition对象signal()
方法,通知当前线程后,当前线程才从await()
返回,但是返回对前提也就是需要获得锁。
三、源码解析
每一个Condition对象包含一个等待队列,该队列是Condition实现的关键,用来实现等待/通知的功能。在Condition中可以拥有多个等待队列。
- 调用await()方法加入等待队列
- 调用signal()方法 从等待队列中移出,加入同步队列开始锁的获取
3.1 等待
当调用await方法时,当前线程会进入等待队列,并且释放锁,线程状态会变为等待状态(CONDITION :-2);当调用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)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 唤醒同步队列中到后继节点;node节点开始自旋获取
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
3.2 通知
调用Condition的signal()方法,会唤醒在等待队列中等待时候最长的节点,然后移动到同步队列当中。
public final void signal() {
// 判断当前线程释放获取锁
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
/**
* 从等待队列中移出 并且添加到同步队列当中
*/
doSignal(first);
}
当执行了doSignal方法后,当前线程从等待队列中移除,await方法中将继续执行,调用acquireQueued(node)
,内部进行自旋获取锁,获取锁当条件:
- 1、前节点是头节点
- 2、获取到同步状态
四、小结
condition
可以用来实现**等待/通知模式。**具体实现逻辑是,等待的线程await加入等待队列,当被通知后,从等待队列中移出,添加到同步队列中,然后继续开始锁到获取(自旋获取)
五、参考
《并发编程的艺术》