1、Condition介绍:
在Java程序中,任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object类上),主要包括wait()、wait(long)、notify()、notifyAll()方法,这些方法与synchronized关键字配合。实现等待/通知模式。
Condition接口也提供了类似Object的监视器方法,与Lock配合可以实现等待/通知模式。Condition可以替代synchronized的线程wait和notify通信方式。
一般都会将Condition对象作为成员变量。
当调用await()方法后,当前线程会 释放锁并在此等待,而其他线程调用Condition对象的signal()方法,通知当前线程后,当前线程 才从await()方法返回,并且在返回前已经获取了锁
public interface Condition {
//当前线程进入等待状态直到被通知(signal)或中断。
void await() throws InterruptedException;
//当前线程进入等待状态直到被通知,该方法不响应中断。
void awaitUninterruptibly();
//当前线程进入等待状态直到被通知、中断或者超时,返回值表示剩余超时时间。
long awaitNanos(long nanosTimeout) throws InterruptedException;
boolean await(long time, TimeUnit unit) throws InterruptedException;
//当前线程进入等待状态直到被通知、中断或者到某个时间。如果没有到指定时间就被通知,方法返回true,否则,表示到了指定时间,返回false。
boolean awaitUntil(Date deadline) throws InterruptedException;
// 唤醒一个等待在Condition上的线程,该线程从等待方法返回前必须获得与Condition相关联的锁。
void signal();
//唤醒所有等待在Condition上的线程,能够从等待方法返回的线程必须获得与Condition相关联的锁。
void signalAll();
}
Condition的实现。创建一个condition对象是通过lock.newCondition(),会new出一个ConditionObject对象,ConditionObject是AQS的一个内部类。
public abstract class AbstractQueuedSynchronizer{
static final class Node {
//标记表示节点正在共享模式中等待
static final Node SHARED = new Node();
//标记表示节点正在独占模式下等待
static final Node EXCLUSIVE = null;
//节点状态
volatile int waitStatus
//当前节点/线程的前驱节点
volatile Node prev
//当前节点/线程的后继节点
volatile Node next;
//加入同步队列的线程引用
volatile Thread thread;
//等待队列中的下一个节点(和Condition配合使用)
Node nextWaiter;
}
//ConditionObject为AQS中的一个内部类
public class ConditionObject implements Condition, java.io.Serializable {
private transient Node firstWaiter;
private transient Node lastWaiter;
}
}
AQS内部维护了一个同步队列Node,如果是独占式锁的话,所有获取锁失败的线程的尾插入到同步队列(带头结点的双向队列),
同样的,condition内部也是使用同样的方式,内部维护了一个 等待队列(不带头结点的单向队列),如果一个线程调用了Condition.await()方法,那么该线程将会 释放锁、构造成节点加入等待队列并且线程状态转换为等待状态。
多次调用lock.newCondition()方法创建多个condition对象,也就是一个lock可以持有多个等待队列。
之前利用Object的wait和notify方式实际上是指在对象Object对象监视器上只能拥有一个同步队列和一个等待队列,
而并发包中的Lock拥有一个同步队列和多个等待队列。如图:
2、Condition.await实现原理
public final void await() throws InterruptedException {
//await方法是响应中断的
if (Thread.interrupted())
throw new InterruptedException();
// 1. 将当前线程加入到等待队列的队尾
Node node = addConditionWaiter();
//释放锁
int savedState = fullyRelease(node);
int interruptMode = 0;
//是否在Condition等待队列中
while (!isOnSyncQueue(node)) {
// 当前线程进入到等待状态
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 若不在 则自旋等待获取到同步状态(即获取到lock)
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
//首先拿到Condition等待队列队尾,如果队尾已经失效了,那就清理掉
unlinkCancelledWaiters();
// 被中断的情况
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
//将当前线程包装成Node
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
//将当前线程封装到Node中
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
//尾插入到等待队列中
t.nextWaiter = node;
lastWaiter = node;
return node;
}
//释放锁
final int fullyRelease(Node node) {
boolean failed = true;
try {
int savedState = getState();
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
//清理队尾失效的情况
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
Node trail = null;
while (t != null) {
Node next = t.nextWaiter;
if (t.waitStatus != Node.CONDITION) {
t.nextWaiter = null;
if (trail == null)
firstWaiter = next;
else
trail.nextWaiter = next;
if (next == null)
lastWaiter = trail;
}
else
trail = t;
t = next;
}
}
3、Condition.signal/signalAll实现原理
public final void signal() {
//判断当前线程是否获取到锁
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//获取等待队列中头节点
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
private void (Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
//1. 将头结点从等待队列中移除
first.nextWaiter = null;
//2. 在transferForSignal中对头结点做处理
} while (!transferForSignal(first) && (first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
//更新状态为0
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
//调用AQS中的enq,将该节点加入到同步队列中自旋排队获取锁
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
//将等待队列中所有节点都放入AQS同步队列中
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
do {
Node next = first.nextWaiter;
first.nextWaiter = null;
transferForSignal(first);
first = next;
} while (first != null);
}
notify和signal都是按线程先进先出的顺序唤醒的