锁升级反映竞争烈度:jvm按无锁→偏向锁→轻量级锁→重量级锁逐级升级;偏向锁几乎零开销,轻量级锁靠cas自旋,重量级锁触发os mutex并引发上下文切换。

看锁升级状态,直接反映竞争烈度
JVM 会根据线程争用情况自动把 synchronized 锁从无锁 → 偏向锁 → 轻量级锁 → 重量级锁逐级升级。不同状态对应不同开销:
- 偏向锁:单线程反复进入,几乎无同步开销,对象头只记录线程 ID
- 轻量级锁:少量线程交替访问,靠 CAS 和栈帧锁记录,自旋不阻塞,但 CPU 消耗上升
- 重量级锁:多个线程激烈争抢,触发操作系统 mutex,线程挂起/唤醒,产生上下文切换,耗时跳升数倍
可通过 JVM 参数 -XX:+PrintSynchronizationStatistics -XX:+UnlockDiagnosticVMOptions 输出锁统计,或用 JFR(Java Flight Recorder)捕获 MonitorEnter 事件,观察锁是否频繁升级到重量级。
测真实吞吐与延迟,别只看单线程
单纯跑单线程 benchmark 会严重低估问题——synchronized 在无竞争时也有 monitor enter/exit 开销,但高并发下的排队效应才是瓶颈核心:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 用 10、50、100 个线程压测同一临界区,观察执行时间非线性增长(如 100 线程耗时是 10 线程的 8 倍以上,就说明锁已成热点)
- 监控线程状态:jstack 抓堆栈,大量线程处于 BLOCKED on java.lang.Object@xxx 即为明显信号
- 对比吞吐量:例如 100 线程调用 1 万次 increment(),若总耗时从 120ms(轻量级)飙升至 860ms(重量级),说明锁争用已主导性能
识别热点对象和锁粒度问题
损耗不仅来自“有没有锁”,更来自“锁了什么”和“谁在争”:
- 共享实例锁(
synchronized method或synchronized(this))容易成为全局瓶颈,尤其像Counter、StringBuffer这类被多处复用的对象 - 静态方法锁(
synchronized static)以 Class 为锁,跨所有实例共享,极易引发跨业务模块的隐式竞争 - 细粒度优化方向:拆分锁对象(如按 key 分段加锁)、改用无锁结构(
AtomicInteger替代synchronized++)、或线程局部缓存(ThreadLocal)减少共享写
对比替代方案,量化收益边界
不是所有场景都必须换,但要清楚换与不换的成本差异:
-
ReentrantLock:支持 tryLock、可中断、公平策略,但需手动释放,且同样存在重量级锁升级;适合需要控制等待行为的场景 -
StampedLock:读多写少时,乐观读避免锁开销,写操作仍需独占,适合缓存、配置类场景 - 无锁原子类(
AtomicInteger、LongAdder):对计数类操作,LongAdder在高并发下比synchronized快 5–10 倍,因内部采用分段累加减少争用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










