一、LockSupport
LockSupport 工具可以帮助我们阻塞或唤醒一个线程,也是构建同步组件的基础工具。
AQS中 对于节点的阻塞和唤醒就是通过LockSupport的park和unpark实现的。
LockSupport 与 对象的 wait/notify的不同在于:
(1) LockSupport不需要获取对象的监视器
(2) 实现机制不同,lockSupport 调用 native的park ,unpark方法。
jdk7 中的LockSupport类结构如下:
关键方法如下:
park() : 阻塞当前线程,调用unpark(Thread)方法或当前线程被中断,才能从park()方法中返回
parkNanos(long nanos) :park上增加超时返回
parkUntil(long deadline): 阻塞当前线程,知道 deadline的时间
unpark(Thread thread): 唤醒处于阻塞状态的线程
park(Object) 这个blocker的方法,主要用于问题排查和系统监控,提供更多的调试信息。
park的实现如下:
二、 Condition
2.1 Condition接口说明
Condition接口提供了类似 Object的监视器方法(wait,notify,notifyAll),与Lock配合可以实现等待/通知模式。
那么Condition接口与监视器方法有什么区别呢?
Condition接口中定义的方法如下:
Object的监视器方法 wait 和 notify 都是调用native的wait,notify 方法,那么Condition是如何实现的呢?
2.2 Condition的实现
先看一个Condition使用的简单例子:
public class ConditionUseCase {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void conditionWait() throws InterruptedException{
lock.lock();
try{
condition.await();
}finally {
lock.unlock();
}
}
public void conditionSignal() throws InterruptedException {
lock.lock();
try{
condition.signal();
}finally {
lock.unlock();
}
}
}
要了解Condition的实现,需要了解一个概念,叫做等待队列。队列中每个节点都包含了线程引用,该线程就是Condition上等待的线程。
当一个线程调用了condition.await() ,那么该线程将会释放锁,构造成节点加入等待队列并进入等待状态。
Condition的实现是AQS的内部类,每个Condition实例都能访问AQS提供的方法。
源码结构如下:
注意 两个成员变量,Node firstWaiter 等待队列的首节点, Node lastWaiter 等待队列的尾节点, Node 使用了AQS的Node,
先看condition.await方法的实现:
public final void await() throws InterruptedException {
// 线程是否中断
if (Thread.interrupted())
throw new InterruptedException();
// 当前线程添加到等待队列
Node node = addConditionWaiter();
// 释放同步状态,释放锁,调用release方法,唤醒后继节点
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
// 添加一个新的Waiter到等待队列
private Node addConditionWaiter() {
Node t = lastWaiter;
// 如果 最后的waiter取消了,清空
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
// 当前线程
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
调用await方法,将当前线程添加到等待队列,如下图:
再看Condition 的 signal()方法的实现:
// 将最长等待的线程 从等待队列移到同步队列
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
// 如果不能改变waitStatus ,失败
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
将节点唤醒的signal方法的图示如下: