当前位置:网站首页>AQS唤醒线程的时候为什么从后向前遍历,我懂了
AQS唤醒线程的时候为什么从后向前遍历,我懂了
2022-07-26 04:57:00 【知识浅谈】
先来熟悉一下代码,挂起和唤醒这两部分
尾部遍历源码
private void unparkSuccessor(Node node) { //获取wait状态 int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0);// 将等待状态waitStatus设置为初始值0 /** * 若后继结点为空,或状态为CANCEL(已失效),则从后尾部往前遍历找到最前的一个处于正常阻塞状态的结点 * 进行唤醒 */ Node s = node.next; if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } if (s != null) LockSupport.unpark(s.thread);//唤醒线程 }注意for循环中的逻辑:从尾部开始向前遍历,找到最前的一个处于正常阻塞状态的结点,直到节点重合(即等于当前节点)
高并发下入队逻辑
既然采用了从尾部遍历的逻辑,那么肯定是为了解决可能会出现的问题。而这个问题就在enq(…)方法中private Node enq(final Node node) { for (;;) { Node t = tail; if (t == null) { // Must initialize //队列为空需要初始化,创建空的头节点 if (compareAndSetHead(new Node())) tail = head; } else { node.prev = t; //set尾部节点 if (compareAndSetTail(t, node)) { //当前节点置为尾部 t.next = node; //前驱节点的next指针指向当前节点 return t; } } } }原子性问题
在该段方法中,将当前节点置于尾部使用了CAS来保证线程安全,但是请注意:在if语句块中的代码并没有使用任何手段来保证线程安全!也就是说,在高并发情况下,可能会出现这种情况:
线程A通过CAS进入if语句块之后,发生上下文切换,此时线程B同样执行了该方法,并且执行完毕。然后线程C调用了unparkSuccessor方法。
假如是从头到尾的遍历形式,线程A的next指针此时还是null!也就是说,会出现后续节点被漏掉的情况。
图解流程
线程A执行CAS将当前节点置为尾部:
原本线程A要执行t.next = node;将node2的next设置为node3,但是,此时发生上下文切换,时间片交由线程B,也就是说,此时node2的next还是null
线程B执行enq逻辑,最终CLH队列如图所示:

此时发生上下文切换,时间片交由线程C,线程C调用了unparkSuccessor方法,假如是从头到尾的遍历形式,在node2就会发现,next指针为null,似乎没有后续节点了。
此时发生上下文切换,时间片交由线程A,A将node2的next=node3。奇怪的现象发生了:对于线程C来说,后续没有node3和node4,但是对于其它线程来说,却出现了这两个节点
结尾
从头部遍历会出现这种问题的原因我们找到了,最后我们再来说说为什么从尾部遍历不会出现这种问题呢?其最根本的原因在于:
node.prev = t;先于CAS执行,也就是说,你在将当前节点置为尾部之前就已经把前驱节点赋值了,自然不会出现prev=null的情况
边栏推荐
- SQL加解密注入详解
- 有ggjj看看这个问题没,是否缓存导致跨域问题?
- What are the well-known to-do apps at home and abroad
- 7、 Restful
- Network Security Learning - permission promotion 2
- data warehouse
- The landing of tdengine in the GPS and AIS scheduling of Zhongtian steel
- 一个sql server查询截止某个日期最新的记录
- Can serial port can 232 can 485 serial port to CANbus bus gateway module can232/485mb converter cancom
- 时代潮流-云原生数据库的崛起
猜你喜欢

Codeforces Round #807 (Div. 2)

分子骨架跃迁工具-DeLinker介绍

SQL加解密注入详解

Rman-06031 cannot convert database keywords

QT compilation error sorting and remote module Download

ES6模块化+CommonJS

Redis解决库存超卖问题

Can serial port can 232 can 485 serial port to CANbus bus gateway module can232/485mb converter cancom

Working principle and application of fast recovery diode

Wsl2 best practices, eliminate difficult xshell and finalshell
随机推荐
Torch slice maintenance
[mathematical modeling] basic knowledge of MATLAB
阿里云工业视觉智能工程师ACP认证——备考
Correspondence between IEC61131 data type and C data type
Database startup message: ora-29702: error occurred in cluster group service
2022河南萌新联赛第(三)场:河南大学 B - 逆序对计数
科技论文翻译,俄语文档的语法有何特点
NFT的几种发行方式你都了解过吗?不同的发行方式有什么优缺点?
2022 Henan Mengxin League game (3): Henan University J - magic number
5、 Domain objects share data
Study of const of constant function
Yapi installation
What are the characteristics of the grammar of Russian documents in the translation of scientific papers
[learning notes] agc041
Redis解决库存超卖问题
[300 + selected interview questions from big companies continued to share] big data operation and maintenance sharp knife interview question column (VIII)
一个sql server查询截止某个日期最新的记录
Recursive implementation of exponential enumeration
3、 @requestmapping annotation
2022河南萌新联赛第(三)场:河南大学 L - 合成游戏