ConditionObject
- 在JUC包下,ConditionObject为了对标Synchronized的wait()和notify()方法的功能,提供了await()和signal()方法。
- 和Synchronized一样必须持lock锁才能调用await()和signal()方法
- 它是基于AQS实现的,在AQS提供了一个单项链表来存储被挂起的线程,当调用await()时候将线程放到Condition链表中,当调用signal()方法时候将线程放到AQS的双向链表中。
基本使用
public class Test {
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(() -> {
try {
lock.lock();
System.out.println("线程1获取锁成功,休眠5S");
Thread.sleep(5000);
System.out.println("线程1挂起线程");
condition.await();
System.out.println("线程1线程被唤醒,操作结束,释放锁!");
lock.unlock();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
Thread.sleep(100);
new Thread(() -> {
try {
lock.lock();
System.out.println("线程2获取锁成功,休眠3S");
Thread.sleep(3000);
System.out.println("线程2执行完毕,释放锁,唤醒线程1");
condition.signal();
lock.unlock();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
}
}
源码分析
Condition构建方法
- 在ReentrantLock中的newCondition()方法中调用了其内部类Sync的newCondition()方法返回一个ConditionObject对象。
- 本质就是返回一个AQS中的ConditionObject对象。
- 一个ReentrantLock可以创建多个ConditionObject对象,在后面的阻塞队列中有用到,读和写使用两个ConditionObject对象,互不影响。
public Condition newCondition() {
return sync.newCondition();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
ConditionObject类
- firstWaiter和lastWaiter记录单项链表的头节点和尾节点
- 用于存放节点信息的Node和AQS双向链表是同一个node类,其中只用nextWaiter属性表示节点关系
- node节点中的 static final int CONDITION = -2; 表示当前节点被放入Condition单项链表中,挂起线程
public class ConditionObject implements Condition, java.io.Serializable {
private static final long serialVersionUID = 1173984872572414699L;
private transient Node firstWaiter;
private transient Node lastWaiter;
public ConditionObject() {
}
}
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;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
private Node addConditionWaiter() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node t = lastWaiter;
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
final boolean isOnSyncQueue(Node node) {
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
if (node.next != null)
return true;
return findNodeFromTail(node);
}
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
final boolean transferAfterCancelledWait(Node node) {
if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
enq(node);
return true;
}
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
signal()唤醒线程
- 被唤醒的线程从condition单项链表中移除,在唤醒过程中将状态不为-2的节点也从链表中移除,直到找到一个可以被唤醒的节点。
- 将唤醒的节点插入到AQS双向链表中
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
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 (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
return false;
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}