深入理解 JUC:AQS 队列同步器( 五 )

方法 AbstractQueuedSynchronizer#fullyRelease 用于释放当前线程持有的资源 , 这也是非常容易理解的 , 毕竟当前线程即将进入等待状态 , 如果持有的资源不被释放 , 将可能导致程序最终被饿死 , 或者死锁 。 方法的实现如下:
final int fullyRelease(Node node) {boolean failed = true;try {// 获取当前线程的同步状态 , 可以理解为持有的资源数量int savedState = this.getState();// 尝试释放当前线程持有的资源if (this.release(savedState)) {failed = false;return savedState;} else {// 释放资源失败throw new IllegalMonitorStateException();}} finally {if (failed) {// 如果释放资源失败 , 则取消当前线程node.waitStatus = Node.CANCELLED;}}}如果资源释放失败 , 则上述方法会将当前线程的状态设置为 CANCELLED , 以退出等待状态 。
方法 AbstractQueuedSynchronizer#isOnSyncQueue 用于检测当前结点是否位于同步队列中 , 方法实现如下:
final boolean isOnSyncQueue(Node node) {// 如果结点位于等待队列 , 或是头结点则返回 falseif (node.waitStatus == Node.CONDITION || node.prev == null) {return false;}// If has successor, it must be on queueif (node.next != null) {return true;}/** node.prev can be non-null, but not yet on queue because the CAS to place it on queue can fail.* So we have to traverse from tail to make sure it actually made it. It will always be near the tail in calls to this method,* and unless the CAS failed (which is unlikely), it will be there, so we hardly ever traverse much.*/// 从后往前检测目标结点是否位于同步队列中return this.findNodeFromTail(node);}如果一个线程所等待的条件被满足 , 则触发条件满足的线程会将等待该条件的一个或全部线程结点从条件队列转移到同步队列 , 此时 , 这些线程将从 ConditionObject#await 方法中退出 , 以参与竞争资源 。
方法 ConditionObject#awaitNanos、ConditionObject#awaitUntil 和 ConditionObject#await(long, TimeUnit) 在上面介绍的 ConditionObject#await 方法的基础上引入了超时机制 , 当一个线程在条件队列中等待的时间超过设定值时 , 线程结点将被从条件队列转移到同步队列 , 参与竞争资源 。 其它执行过程与 ConditionObject#await 方法相同 , 故不再展开 。
下面来分析一下 ConditionObject#awaitUninterruptibly 方法 , 由方法命名可以看出该方法相对于 ConditionObject#await 方法的区别在于在等待期间不响应中断 。 方法实现如下:
public final void awaitUninterruptibly() {// 将当前线程添加到等待队列末尾 , 等待状态为 CONDITIONNode node = this.addConditionWaiter();// 释放当前线程持有的资源int savedState = fullyRelease(node);boolean interrupted = false;// 如果当前结点位于条件队列中 , 则循环while (!isOnSyncQueue(node)) {// 阻塞当前线程LockSupport.park(this);if (Thread.interrupted()) {// 标识线程等待期间被中断 , 但不立即响应interrupted = true;}}// 自旋获取资源 , 返回 true 则说明等待期间被中断过if (acquireQueued(node, savedState) || interrupted) {// 响应中断selfInterrupt();}}如果线程在等待期间被中断 , 则上述方法会用一个字段进行记录 , 并在最后集中处理 , 而不会因为中断而退出等待状态 。
通知:signal调用 await 方法会将线程对象自身加入到条件队列中进行等待 , 而 signal 通知方法则用于将一个或全部的等待线程从条件队列转移到同步队列 , 以参与竞争资源 。 ConditionObject 定义了两个通知方法:signal 和 signalAll , 前者用于将条件队列的头结点(也就是等待时间最长的结点)从条件队列转移到同步队列 , 后者用于将条件队列中所有处于等待状态的结点从条件队列转移到同步队列 。 下面分别来分析一下这两个方法的实现 。


推荐阅读