4.4 signal唤醒signal唤醒的流程:
文章插图
唤醒条件队列的头节点,并追加到同步队列末尾 。
// 唤醒条件队列的头节点public final void signal() {// 1. 只有持有锁的线程才能调用signal方法if (!isHeldExclusively())throw new IllegalMonitorStateException();// 2. 找到条件队列的头节点Node first = firstWaiter;if (first != null)// 3. 开始唤醒doSignal(first);}// 实际的唤醒方法private void doSignal(Node first) {do {// 4. 从条件队列中移除头节点if ((firstWaiter = first.nextWaiter) == null)lastWaiter = null;first.nextWaiter = null;// 5. 使用死循环,一定要转移一个节点到同步队列} while (!transferForSignal(first) &&(first = firstWaiter) != null);}
到底是怎么转移到同步队列末尾的?// 实际转移方法final boolean transferForSignal(Node node) {// 1. 把节点状态从CONDITION改成0if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))return false;// 2. 使用死循环的方式,追加到同步队列末尾(前面已经讲过)Node p = enq(node);int ws = p.waitStatus;// 3. 把前驱节点状态设置SIGNAL(通知他,别忘了唤醒老弟)if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))LockSupport.unpark(node.thread);return true;}
5. 总结看完整个AQS的源码,是不是完全理解了AQS加锁、释放锁、以及同步队列和条件队列数据流转的逻辑了 。文章插图
连AQS这么复杂的源码你都搞清楚了,下篇带你一块学习ReentrantLock源码,应该就轻松多了 。
我是「一灯架构」,如果本文对你有帮助,欢迎各位小伙伴点赞、评论和关注,感谢各位老铁,我们下期见
文章插图
经验总结扩展阅读
- 定位java程序中占用cpu最高的线程堆栈信息
- Java8新特性—四大内置函数式接口
- 2 java安全之CC1浅学
- JVM调优工具使用手册
- 记一次多个Java Agent同时使用的类增强冲突问题及分析
- Java使用lamda表达式简化代码
- 1 java安全之CC1浅学
- SpringBoot 01: JavaConfig + @ImportResource + @PropertyResource
- 一 OpenMP 教程 深入人剖析 OpenMP reduction 子句
- 1 Java安全之反序列化