Java自适应自旋锁由JVM动态调整:依据锁历史成功率(加权移动平均)、持有线程状态(RUNNABLE则多旋)、CPU核数与负载、竞争线程数,按锁对象粒度独立优化自旋次数。

Java 中自适应自旋锁不靠固定参数,而是由 JVM 在运行时“边试边学”,根据同一把锁的历史表现和当前系统状态动态决定本次该自旋几次。
看这把锁最近成没成
每个被 synchronized 修饰的对象在 JVM 内部都隐式关联一段统计信息。JVM 会记住它最近几次自旋是否成功抢到锁:
- 上次自旋成功 → 推断这次也容易成功,下次自旋次数大概率翻倍(比如从 10 次升到 20 次)
- 连续两次失败 → 认为锁持有时间偏长或竞争激烈,下次可能减半(如 10 → 5 → 2),甚至直接跳过自旋
- 成功率按加权移动平均更新,新结果影响更大,让调整更灵敏
看拿着锁的线程还在不在跑
JVM 会检查持有该锁的线程当前状态:
- 如果线程是 RUNNABLE 状态(没被挂起、没 sleep、没卡在 IO 上),说明锁很可能马上释放,值得多等几轮
- 如果线程已 BLOCKED 或 WAITING,大概率要等很久,JVM 就会压低自旋意愿,快速退避
看 CPU 和竞争线程够不够用
自旋不是孤立决策,它和硬件与负载强相关:
立即学习“Java免费学习笔记(深入)”;
- 多核 CPU 且当前负载不高 → 更愿意让线程自旋,避免上下文切换开销
- 单核 CPU 或 CPU 利用率超过 90% → 自旋意义不大,反而浪费资源,会主动限制或跳过
- 竞争线程数远超 CPU 核心数(比如 > 核心数 × 2)→ 触发智能降级,倾向直接走重量级锁流程
调整不是全局一刀切
自旋次数的调整是以锁对象为单位的,不同对象互不影响:
- 一个高频短临界区的计数器对象,可能被调高到 50 次自旋
- 一个偶尔使用的配置加载锁,可能长期维持在 2–3 次,甚至归零
- 这种粒度保证了不同业务场景下的锁行为能各自适配,不会互相拖累


















