本文主要是介绍J.U.C — Locks — ReentrantLock(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
条件变量Condition
Condition实现了synchronized同步器的wait/notify/notifyAll的功能,Condition接口提供的API如下:
Condition需要与Lock绑定,一个Lock可以有多个Condition,获取Condition的方式是lock.newCondition()。Condition的实现类在AQS中的ConditionObject,类部维持了一个等待队列:
- 获取Condition
lock.newCondition() -->// ReentrantLock
public Condition newCondition() {return sync.newCondition();
}// ReentrantLock.Sync
final ConditionObject newCondition() {return new ConditionObject();
}-->// AQS.ConditionObjectpublic ConditionObject() { }
- await()
public final void await() throws InterruptedException {if (Thread.interrupted()) // 如果当前线程被终端,抛出异常throw new InterruptedException();Node node = addConditionWaiter(); // 1. 将当前线程添加到Condition队列int savedState = fullyRelease(node); // 2. 释放锁int interruptMode = 0;while (!isOnSyncQueue(node)) { // 3. 自旋直到被signal或signalAll唤醒LockSupport.park(this); // 挂起当前线程if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;}if (acquireQueued(node, savedState) && interruptMode != THROW_IE) // 4. 自旋去获取锁interruptMode = REINTERRUPT;if (node.nextWaiter != null) // clean up if cancelledunlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);}// 1.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;elset.nextWaiter = node;lastWaiter = node;return node;}// 2.final int fullyRelease(Node node) {boolean failed = true;try {int savedState = getState();if (release(savedState)) { // 调用release方法释放锁failed = false;return savedState;} else {throw new IllegalMonitorStateException();}} finally {if (failed)node.waitStatus = Node.CANCELLED;}}// 3.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 queuereturn true;return findNodeFromTail(node);}private boolean findNodeFromTail(Node node) { // 在sync队列中从尾部到头部查找是不是在sync队列中Node t = tail;for (;;) {if (t == node)return true;if (t == null)return false;t = t.prev;}}
- signal()
public final void signal() {if (!isHeldExclusively()) // 1. 判断是不是当前线程持有锁,只有持有锁的线程能唤醒其他等待的线程throw new IllegalMonitorStateException();Node first = firstWaiter;if (first != null)doSignal(first); // 2. 通知Condition队列中的等待最长时间的线程,即firstWaiter}// ReentrantLock.Sync
// 1.
protected final boolean isHeldExclusively() {return getExclusiveOwnerThread() == Thread.currentThread();
}// 2.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); // 将节点加入sync队列int ws = p.waitStatus;if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))LockSupport.unpark(node.thread);return true;}
事例
假设现在有三个线程陆续调用同一个condition的await- 开始状态:thread-1获取锁
-
- thread-1调用await():
用thread-1创建节点,并设置waitStatus= -2(Condition),再将thread-1加入Condition队列,队列为空,将firstWaiter和lastWaiter设为thread-1;调用release释放thread-1拥有的锁,并从Sync队列中移除节点;自旋等待唤醒
- thread-2调用await():
- thread-3调用await():
- 当收到signal信号后,会从condition队列中从头开始将节点移到sync队列,并唤醒自旋获取锁
这篇关于J.U.C — Locks — ReentrantLock(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!