先看完AQShttps://blog.csdn.net/zgsxhdzxl/article/details/95032337,再来看比较容易理解。
condition可以对线程进行阻塞和唤醒。类似wait/notify,不同的是condition可以方便地对持有锁的线程进行阻塞和唤醒。
我们知道AQS中有一个队列是同步队列,condition也有一个队列叫等待队列,不过同步队列是双向的,等待队列是单向的。
![](https://img-blog.csdnimg.cn/20190714215652288.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pnc3hoZHp4bA==,size_16,color_FFFFFF,t_70)
-
使用示例:
static Lock lock = new ReentrantLock();
static Lock lock2 = new ReentrantLock();
static Condition one = lock.newCondition();
static Condition two = lock2.newCondition();
public static void main(String[] args) throws InterruptedException {
Thread oneThread = new Thread(() -> {
try {
lock.lock();
one.await();
System.out.println("1");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
});
Thread twoThread = new Thread(() -> {
try {
lock2.lock();
two.await();
System.out.println("2");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
});
oneThread.start();
twoThread.start();
Thread.sleep(200);
lock.lock();
one.signal();
lock.unlock();
}
-
主要方法
- await
释放锁,线程被挂起,同Object.wait()类似。
方法总览,大致就是将获得锁的节点插入到等待队列,释放锁持有的锁,唤醒下一个节点,之后进入睡眠等待被唤醒。
![](https://img-blog.csdnimg.cn/20190714233413191.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pnc3hoZHp4bA==,size_16,color_FFFFFF,t_70)
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 将该节点插入到等待队列队尾
Node node = addConditionWaiter();
// 释放锁,返回值是释放锁之前的 state 值
// await() 之前,当前线程是必须持有锁的,这里肯定要释放掉
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)
// 继续清理不是CONDITION的节点
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
将节点加入到等待队列
// 将该节点插入到等待队列队尾
private Node addConditionWaiter() {
Node t = lastWaiter;
// 如果节点状态不是CONDITION,则表示节点需要被清除
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;
}
// 清除掉等待队列中状态不是CONDITION的节点
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
Node trail = null;
while (t != null) {
// 获取头节点的后驱节点
Node next = t.nextWaiter;
// 如果节点状态不是CONDITION,则表示节点需要被清除
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;
}
}
释放锁
// 完全释放持有的锁
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;
}
}
判断是否在同步队列中
// 判断节点是否在同步队列中
final boolean isOnSyncQueue(Node node) {
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
if (node.next != null) // If has successor, it must be on queue
return true;
return findNodeFromTail(node);
}
// 判断是否节点是否在同步队列中
private boolean findNodeFromTail(Node node) {
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
线程被唤醒之后,判断线程是否被中断,并且将线程加入到同步队列中。
// 判断线程是否被中断
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
final boolean transferAfterCancelledWait(Node node) {
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
// 将节点插入到同步队列尾部
enq(node);
return true;
}
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
之后便是去获取锁。
- signal
将Condition.await()挂起的第一个线程唤醒。
![](https://img-blog.csdnimg.cn/20190714233509831.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pnc3hoZHp4bA==,size_16,color_FFFFFF,t_70)
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) {
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;
}