如何通过 ConcurrentLinkedQueue 的 HOPS 机制大幅降低 CAS 操作频率以优化高并发入队效率?
- 内容介绍
- 文章标签
- 相关推荐
本文共计672个文字,预计阅读时间需要3分钟。
HOPS并非公开API或配置项,而是Doug Lea在ConcurrentLinkedQueue内部使用的一种跳跃计数策略:
tail 节点为什么容易过期?怎么触发 HOPS 跳转
ConcurrentLinkedQueue 的 tail 并非实时指向物理尾节点,而是一个“乐观缓存”。只要 tail 的 next 字段非 null,就说明它已不是真正尾部;此时若继续用它做 casNext,大概率失败。HOPS 就是在这种判断成立时,让线程放弃 tail,转而从 tail.next 开始向后遍历,直到找到 next == null 的节点——这个过程可能跳过若干中间节点,所以叫 “hop”。
- 触发条件:当前 tail 节点的
next != null,且该next不是哨兵节点(即不是p == q场景) - 实际跳转逻辑藏在 offer 循环里:
else p = (p != t && t != (t = tail)) ? t : q;—— 这里的q就是p.next,本质就是 hop 一步 - 注意:HOPS 不是固定步长,而是“一次跳一格 next”,但因循环中多次执行,效果是快速甩开陈旧 tail
你无法控制 HOPS,但可以避免破坏它的前提
你不能调用任何方法开启/关闭 HOPS,它完全由内部状态驱动。
本文共计672个文字,预计阅读时间需要3分钟。
HOPS并非公开API或配置项,而是Doug Lea在ConcurrentLinkedQueue内部使用的一种跳跃计数策略:
tail 节点为什么容易过期?怎么触发 HOPS 跳转
ConcurrentLinkedQueue 的 tail 并非实时指向物理尾节点,而是一个“乐观缓存”。只要 tail 的 next 字段非 null,就说明它已不是真正尾部;此时若继续用它做 casNext,大概率失败。HOPS 就是在这种判断成立时,让线程放弃 tail,转而从 tail.next 开始向后遍历,直到找到 next == null 的节点——这个过程可能跳过若干中间节点,所以叫 “hop”。
- 触发条件:当前 tail 节点的
next != null,且该next不是哨兵节点(即不是p == q场景) - 实际跳转逻辑藏在 offer 循环里:
else p = (p != t && t != (t = tail)) ? t : q;—— 这里的q就是p.next,本质就是 hop 一步 - 注意:HOPS 不是固定步长,而是“一次跳一格 next”,但因循环中多次执行,效果是快速甩开陈旧 tail
你无法控制 HOPS,但可以避免破坏它的前提
你不能调用任何方法开启/关闭 HOPS,它完全由内部状态驱动。

