轻量级锁适用于线程交替执行、同步块执行时间短的低竞争场景,依赖cas自旋避免上下文切换;重量级锁适用于高竞争或长临界区场景,通过操作系统阻塞线程以节省cpu。

轻量级锁和重量级锁不是手动选择的,而是 JVM 根据运行时锁竞争情况自动切换的两种状态。理解它们的适用场景,关键在于识别线程访问模式和同步块执行特征。
轻量级锁适合短时间、低频竞争的场景
当多个线程交替进入同一同步块,且每次持有锁的时间很短(通常在几十到几百纳秒级),JVM 会倾向于维持轻量级锁状态。它依赖 CAS 操作尝试获取锁,失败后不立即阻塞线程,而是让其自旋等待一小段时间。
- 典型例子:高频调用的 getter/setter 方法中包含简单字段赋值或校验逻辑
- 优势在于避免线程挂起与唤醒的上下文切换开销
- 但自旋会消耗 CPU,若锁长时间未释放,自旋反而降低整体吞吐量
重量级锁适合长时间持有或高竞争强度的场景
一旦轻量级锁的自旋失败次数超过阈值,或检测到多个线程持续争抢同一锁,JVM 就会将锁升级为重量级锁。此时线程无法自旋,直接进入操作系统等待队列,由内核调度唤醒。
- 典型例子:数据库连接池获取连接、文件写入、复杂业务事务处理等耗时操作
- 虽然带来线程阻塞和上下文切换成本,但能节省 CPU 资源,更适合长临界区
- 适用于锁被频繁争抢且单次持有时间明显长于线程切换开销的情况
偏向锁是轻量级锁的前置优化,但不等于“轻量级”
偏向锁并非轻量级锁的子集,而是另一种独立优化路径。它只在无竞争、单一线程反复进入同步块时生效。一旦发生竞争,就会撤销偏向状态,直接升级为轻量级锁(而非跳过)。
- 适用于 Web 应用中大量对象被单个线程初始化或独占访问的场景(如 ThreadLocalMap、部分缓存对象)
- 撤销偏向锁本身有代价,若对象生命周期短或很快出现多线程访问,反而得不偿失
- Java 15+ 默认关闭偏向锁,因现代应用中该场景比例下降,且撤销成本不可忽略
实际判断依据不是代码写法,而是运行时行为
你无法通过加锁方式(synchronized 块 or 方法)决定锁类型,JVM 会根据对象头标记、线程争抢频率、自旋成功率等动态决策。可通过 -XX:+PrintSynchronizationStatistics 或 JFR(Java Flight Recorder)观察锁升级过程。
- 监控指标包括:偏向撤销次数、轻量级锁自旋失败率、重量级锁阻塞线程数
- 若发现大量轻量级锁快速升级为重量级锁,说明临界区可能过长或存在热点锁
- 若轻量级锁自旋占比高但 CPU 使用率飙升,需考虑减少锁粒度或改用无锁结构(如 AtomicInteger、ConcurrentHashMap)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











