ps:要想理解Condition原理,需要先了解AQS,不了解AQS的可以看先之前的文章->aqs源码解析
在Synchronized加锁状态时,是使用wait/notify/notifyAll进行线程间的通信。那么在使用ReentrantLock加锁时,是如何实现线程间通信问题的呢?在JUC中既然提供了Lock,也提供了用作其线程间通信的方式,再次引入了Condition。
我们先来看一下Condition是如何使用的:
唤醒线程:
public class ConditionNotify implements Runnable {
private Lock lock;
private Condition condition;
public ConditionNotify(Lock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
try {
lock.lock();
System.out.println("begin - notify");
condition.signal();
System.out.println("end - notify");
}catch (Exception e){
}finally {
lock.unlock();
}
}
}
阻塞线程:
public class ConditionWait implements Runnable {
private Lock lock;
private Condition condition;
public ConditionWait(Lock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
try {
lock.lock();
System.out.println("begin - wait");
condition.await();
System.out.println("end - wait");
}catch (InterruptedException e){
}finally {
lock.unlock();
}
}
}
运行:
public class Main {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// 保证两个线程获取的是同一把锁 和 同一个COndition
new Thread(new ConditionWait(lock, condition)).start();
new Thread(new ConditionNotify(lock, condition)).start();
}
}
假如两个线程A、B同时争抢同一把锁,线程A先获取到锁的时候,线程B出入等待队列中,队列状态如下:
final ConditionObject newCondition() {
return new ConditionObject();
}
Condition对象使用执行lock.newCondition()获取的,会创建一个ConditionObject对象返回。我们先来看一下ConditionObject的结构:
private transient Node firstWaiter;
/** Last node of condition queue. */
private transient Node lastWaiter;
它有两个成员对象(很重要),分别表示头结点和尾节点构成一个单向队列,当调用await方法时,会将线程加入的这个队列中,下文会讲。
线程A获取到锁处于运行状态,当调用Condition的await方法时,具体做了哪些事情:
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 将线程加入到Condition队列中
Node node = addConditionWaiter();
// 释放锁
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);
}
await方法调用addConditionWaiter方法,将线程加入到Condition队列中去:
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
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方法中调用fullyRelease释放锁,后续走AQS逻辑会从AQS队列中唤醒等待线程B,这个时候线程B获取到锁,队列状态转换如下:
当线程B运行时,会调用signal方法,signal方法逻辑如下:
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
// 将Condition队列中的线程移除,加入到
doSignal(first);
}
final boolean transferForSignal(Node node) {
/*
* If cannot change waitStatus, the node has been cancelled.
*/
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
/*
* Splice onto queue and try to set waitStatus of predecessor to
* indicate that thread is (probably) waiting. If cancelled or
* attempt to set waitStatus fails, wake up to resync (in which
* case the waitStatus can be transiently and harmlessly wrong).
*/
// 加入到AQS队列
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
// 如果没有线程占用锁,就唤醒该线程
LockSupport.unpark(node.thread);
return true;
}
signal方法执行后,将Condition队列中的线程加入到AQS队列,(如果这个时候线程B运行完释放了锁就会唤醒线程B,)队列状态如下:
直到两个线程都运行完成,两个队列都会为空。