重量级锁和自旋锁是动态适配而非二选一的关系;jvm根据临界区耗时、竞争强度和cpu资源自动选择,短操作倾向自旋锁(忙等不释放cpu),长操作倾向重量级锁。

重量级锁和自旋锁不是“二选一”的关系,而是根据临界区执行时间、线程竞争强度、CPU资源可用性动态适配的两种机制。JVM(尤其是 synchronized)内部会自动权衡,开发者通常无需手动切换,但理解其判断逻辑能帮你写出更高效的并发代码。
看临界区耗时:短操作用自旋,长操作用重量级
自旋锁本质是“忙等”——线程在用户态反复检查锁是否释放,不交出 CPU。这只有在锁持有时间极短(通常建议
- 若临界区涉及 I/O、网络调用、数据库查询或复杂计算,必然导致长时间持锁,此时自旋只会白耗 CPU,JVM 会很快让争用线程进入阻塞,升级为重量级锁。
- 重量级锁依赖操作系统互斥量,线程挂起后彻底释放 CPU,适合毫秒级甚至更长的同步块。
看竞争激烈程度:低竞争倾向自旋,高竞争倒向重量级
自旋效果依赖“大概率能很快拿到锁”。当只有 1–2 个线程争抢,且锁释放频率高,自旋成功率高;一旦线程数增多或锁被长期占用,自旋失败率上升,CPU 被大量空转线程占据,系统吞吐反而下降。
- 典型低竞争场景:单生产者-单消费者队列的头尾指针更新。
- 典型高竞争场景:热点缓存的全局统计计数器、连接池的 acquire/release。
- JVM 默认自旋次数有限(如 10 次),超限即阻塞,避免无谓消耗。
看运行环境:多核友好自旋,单核慎用
自旋的前提是“等待线程和持有线程能并行运行”。在多核 CPU 上,一个核跑持有线程,另一个核跑自旋线程,效率有保障;但在单核或超线程受限环境,自旋线程会挤占持有线程的调度时间,延长锁释放周期,形成恶性循环。
- 现代服务器基本都是多核,但容器化部署可能限制可用核数,需留意实际分配情况。
- 重量级锁不受此限制,阻塞后由内核统一调度,对 CPU 核数不敏感。
JVM 实际怎么选:锁升级路径决定行为
synchronized 不是静态选择某一种锁,而是一套渐进式策略:
- 无竞争 → 偏向锁(几乎零开销)
- 偶发轻度竞争 → 轻量级锁 + 自旋(用户态 CAS 尝试)
- 持续竞争或自旋失败 → 升级为重量级锁(内核态挂起)
这个过程由对象头 Mark Word 的锁标志位控制,全程自动。你可通过 JVM 参数(如 -XX:-UseBiasedLocking 或 -XX:PretenureSizeThreshold)干预,但一般推荐保持默认,让 JVM 根据运行时特征自适应。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











