商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Java 中轻量级锁如何通过 CAS 保障线程同步性能

Java 中轻量级锁如何通过 CAS 保障线程同步性能

  发布于2026-07-07 阅读(0)

扫一扫,手机访问

轻量级锁通过CAS抢锁并自旋等待,失败后升级为重量级锁;它在用户态完成同步,避免内核态切换开销,适用于短临界区、低频竞争场景。

Java 中轻量级锁如何通过 CAS 保障线程同步性能

Java 里的轻量级锁,说到底就是靠CAS这套原子指令来完成线程同步。它的核心思路很简单:遇到竞争先别急着挂起线程,让它在用户态自旋一会儿,实在不行再走阻塞那条路——目的就是把昂贵的用户态↔内核态切换压到最少。不是要彻底消灭竞争,而是让那些短时、低频的争夺在用户态快速消化掉,吞吐量自然就上来了。

那具体怎么通过CAS抢锁呢?当线程进入 synchronized 同步块的那一刻,JVM 先瞄一眼对象头的标志位:如果显示是“无锁”(标志位 01),就在当前线程的栈帧里建一个锁记录(Lock Record),然后用 CAS 指令尝试把对象头的 Mark Word 替换成指向这个锁记录的指针。

  • 替换成功 → 线程直接拿到轻量级锁,继续往下执行,整个过程没有挂起、没有调度、没有内核掺和;
  • 替换失败 → 说明锁已经被其他线程占着了。这时候不急着阻塞,而是进入自旋:反复用 CAS 去检查对象头是不是已经恢复成无锁状态或者原值了。

为什么自旋比挂起更高效?这里有个量级上的差异。线程挂起需要操作系统从用户态切到内核态,保存寄存器、刷新 TLB、触发调度器,一次切换少说几百纳秒到微秒级。而 CAS 自旋不过是 CPU 在用户态反复执行一条原子指令(比如 cmpxchg),成本极低。自旋期间线程保持运行态,完全避免了上下文切换的损耗。这特别适合锁持有时间很短(几十纳秒级别)、竞争不激烈但偶尔会碰到的情景。当然,如果自旋超过某个阈值(默认大概是 10 次)还是没抢到,那就升级成重量级锁,真正把线程挂起来。

单靠自旋远远不够,JVM 还为轻量级锁做了几层协同优化:

  • 自适应自旋:JVM 会根据前一次在这个锁上自旋是否成功,动态调整这次的自旋次数。如果上一次自旋成功了,下次就多转几圈;上次白忙活了,就少转两圈,避免空耗。
  • 锁膨胀控制:一旦检测到同一把锁频繁竞争——比如连续两次自旋都失败,JVM 会提前把它升级为重量级锁,防止无效自旋白白吃掉 CPU。
  • 代码层面的配合:同步块里尽量别放耗时操作,比如 I/O、sleep、复杂的计算逻辑。只有保证锁持有时间足够短,轻量级锁才能一直保持“轻量”状态。

当然,CAS 和轻量级锁也不是万能的。它们有很明确的适用边界:

  • 在高并发、长临界区的场景下,自旋会变成 CPU 的“电暖炉”——浪费资源,还不如及时挂起省事;
  • CAS 本身不保证可见性,需要搭配 volatile 或内存屏障使用,不过轻量级锁内部已经封装了这些处理;
  • ABA 问题理论上存在,但轻量级锁依赖的是对象头 Mark Word 中“版本号+线程ID”的组合判断,天然避开了纯数值型的 ABA 风险。
本文转载于:https://www.php.cn/faq/2782337.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注