前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >synchronized 的锁升级机制详解

synchronized 的锁升级机制详解

原创
作者头像
麦辣鸡腿堡
发布2025-03-19 10:28:15
发布2025-03-19 10:28:15
1320
举报
文章被收录于专栏:面试面试

synchronized 是 Java 中实现线程同步的核心机制,其锁状态会随着竞争激烈程度动态升级,以提高并发性能。从 无锁重量级锁 的升级过程包括四个阶段,且 不可逆。以下是具体流程及原理:

1. 无锁状态
  • 特点: 对象初始化时处于无锁状态,此时没有线程持有锁。Mark Word(对象头的一部分)中存储对象的哈希码、分代年龄等信息,锁标志位为 01
  • 适用场景: 单线程环境或未发生竞争的情况。
2. 偏向锁
  • 设计目的: 减少同一线程重复获取锁的开销(如单线程执行同步代码块)
  • 实现原理
    • 首次获取锁时,JVM 将线程 ID 记录到 Mark Word 中,并将锁标志位设为 01(偏向锁标识位为 1)。
    • 后续同一线程访问时,无需 CAS 操作,直接检查线程 ID 即可快速获取锁
  • 升级条件: 当其他线程尝试竞争锁时,偏向锁撤销(需等待全局安全点),并升级为轻量级锁
3. 轻量级锁
  • 设计目的: 减少多线程交替执行时的阻塞开销,避免直接升级到重量级锁
  • 实现原理
    • 线程通过 CAS 操作将 Mark Word 替换为指向栈帧中锁记录的指针,锁标志位变为 00
    • 若 CAS 失败(存在竞争),线程进入自旋等待(空转循环),尝试有限次数的重试(默认 10 次,JDK 1.7 后引入适应性自旋)
  • 升级条件
    • 自旋超过阈值仍无法获取锁。
    • 竞争线程数超过 1(如三个线程同时竞争)
4. 重量级锁
  • 设计目的: 应对高并发竞争场景,通过操作系统互斥量(Mutex)实现阻塞机制
  • 实现原理
    • Mark Word 中存储指向 Monitor 对象(C++ 实现)的指针,锁标志位变为 10
    • 未获取锁的线程进入阻塞队列,由操作系统调度唤醒
  • 缺点: 涉及用户态到内核态的切换,性能开销较大

锁升级的关键特性

  1. 不可逆性: 锁只能从低级别(如偏向锁)升级到高级别(如重量级锁),无法降级。这是为了避免频繁状态切换的开销
  2. 动态适应性: JVM 根据线程竞争情况自动选择锁策略,例如:
    • 低竞争:偏向锁或轻量级锁减少开销。
    • 高竞争:重量级锁保证线程安全

锁升级的触发条件与流程

锁状态

触发条件

Mark Word 变化

无锁

对象初始化时

哈希码 + 分代年龄 + 锁标志位 01

偏向锁

首次线程访问同步块

线程 ID + 锁标志位 01(偏向标识位 1)

轻量级锁

多线程交替竞争或偏向锁撤销

栈帧锁记录指针 + 锁标志位 00

重量级锁

自旋失败或竞争线程数过多

Monitor 指针 + 锁标志位 10

锁升级的优缺点

优点

缺点

减少无竞争场景下的同步开销 5 54

重量级锁的阻塞机制导致高延迟 11 72

自适应不同并发场景,平衡性能与安全性 11

锁升级不可逆,可能过度升级到重量级锁 54

实际应用建议

  1. 避免过度同步: 缩小同步代码块范围,减少锁竞争概率。
  2. 监控锁状态: 使用工具(如 JOL)查看对象头信息,分析锁升级过程
  3. 替代方案: 在高并发场景下,可结合 ReentrantLockStampedLock 提升灵活性

通过理解锁升级机制,开发者可以更好地优化多线程程序的性能,避免因锁竞争导致的性能瓶颈

代码语言:java
复制
import org.openjdk.jol.info.ClassLayout;

public class LockUpgradeExample {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个对象
        Object obj = new Object();
        System.out.println("===== 初始状态(无锁) =====");
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());

        // 偏向锁延迟(默认 4s),确保偏向锁生效
        Thread.sleep(5000);

        // 首次获取锁,触发偏向锁
        synchronized (obj) {
            System.out.println("===== 偏向锁状态 =====");
            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
        }

        // 创建多个线程竞争锁,触发轻量级锁
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                synchronized (obj) {
                    System.out.println("===== 轻量级锁状态 =====");
                    System.out.println(ClassLayout.parseInstance(obj).toPrintable());
                }
            }).start();
            Thread.sleep(1000);
        }

        // 高竞争场景,触发重量级锁
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                synchronized (obj) {
                    System.out.println("===== 重量级锁状态 =====");
                    System.out.println(ClassLayout.parseInstance(obj).toPrintable());
                }
            }).start();
        }
    }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 无锁状态
  • 2. 偏向锁
  • 3. 轻量级锁
  • 4. 重量级锁
  • 锁升级的关键特性
  • 锁升级的触发条件与流程
  • 锁升级的优缺点
  • 实际应用建议
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档