再看一下shouldParkAfterFailedAcquire方法,是怎么找到将自己唤醒的节点的?为什么要找这个节点?
// 加入同步队列后,找到能将自己唤醒的节点private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {int ws = pred.waitStatus;// 1. 如果前驱节点的状态已经是SIGNAL状态(释放锁后,需要唤醒后继节点),就无需操作了if (ws == Node.SIGNAL)return true;// 2. 如果前驱节点的状态是已取消,就继续向前遍历if (ws > 0) {do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);pred.next = node;} else {// 3. 找到了不是取消状态的节点,把该节点状态设置成SIGNALcompareAndSetWaitStatus(pred, ws, Node.SIGNAL);}return false;}
从代码中可以很清楚的看到,目的就是为了找到不是取消状态的节点,并把该节点的状态设置成SIGNAL 。
状态是SIGNAL的节点,释放锁后,需要唤醒其后继节点 。
简单理解就是:小弟初来乍到,特意来知会老大一声,有好事,多通知小弟 。
再看一下释放锁的逻辑 。
4.2 释放锁释放锁的流程如下:
文章插图
释放锁的代码逻辑比较简单:
// 释放锁public final boolean release(int arg) {// 1. 先尝试释放锁,如果时候成功,则设置state-1,exclusiveOwnerThread=null(由子类实现)if (tryRelease(arg)) {Node h = head;// 2. 如果同步队列中还有其他节点,就唤醒下一个节点if (h != null && h.waitStatus != 0)// 3. 唤醒其后继节点unparkSuccessor(h);return true;}return false;}
再看一下唤醒后继节点的方法// 唤醒后继节点private void unparkSuccessor(Node node) {int ws = node.waitStatus;// 1. 如果头节点不是取消状态,就重置成初始状态if (ws < 0)compareAndSetWaitStatus(node, ws, 0);Node s = node.next;// 2. 如果后继节点是null或者是取消状态if (s == null || s.waitStatus > 0) {s = null;// 3. 从队尾开始遍历,找到一个有效状态的节点for (Node t = tail; t != null && t != node; t = t.prev)if (t.waitStatus <= 0)s = t;}// 3. 唤醒这个有效节点if (s != null)LockSupport.unpark(s.thread);}
4.3 await等待await等待的流程:文章插图
持有锁的线程可以调用await方法,作用是:释放锁,并追加到条件队列末尾 。
【硬核剖析Java锁底层AQS源码,深入理解底层架构设计】
// 等待方法public final void await() throws InterruptedException {// 如果线程已中断,则中断if (Thread.interrupted())throw new InterruptedException();// 1. 追加到条件队列末尾Node node = addConditionWaiter();// 2. 释放锁int savedState = fullyRelease(node);int interruptMode = 0;// 3. 有可能刚加入条件队列就被转移到同步队列了,如果还在条件队列,就可以放心地挂起自己while (!isOnSyncQueue(node)) {LockSupport.park(this);if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;}// 4. 如果已经转移到同步队列,就尝试获取锁if (acquireQueued(node, savedState) && interruptMode != THROW_IE)interruptMode = REINTERRUPT;if (node.nextWaiter != null)// 5. 清除条件队列中已取消的节点unlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);}
再看一下addConditionWaiter方法,是怎么追加到条件队列末尾的?// 追加到条件队列末尾private Node addConditionWaiter() {Node t = lastWaiter;// 1. 清除已取消的节点,找到有效节点if (t != null && t.waitStatus != Node.CONDITION) {unlinkCancelledWaiters();t = lastWaiter;}// 2. 创建Node节点,状态是-2(表示处于条件队列)Node node = new Node(Thread.currentThread(), Node.CONDITION);// 3. 追加到条件队列末尾if (t == null)firstWaiter = node;elset.nextWaiter = node;lastWaiter = node;return node;}
经验总结扩展阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 定位java程序中占用cpu最高的线程堆栈信息
- Java8新特性—四大内置函数式接口
- 2 java安全之CC1浅学
- JVM调优工具使用手册
- 记一次多个Java Agent同时使用的类增强冲突问题及分析
- Java使用lamda表达式简化代码
- 1 java安全之CC1浅学
- SpringBoot 01: JavaConfig + @ImportResource + @PropertyResource
- 一 OpenMP 教程 深入人剖析 OpenMP reduction 子句
- 1 Java安全之反序列化