synchronized 全解析:从用法到底层原理的全面剖析

摘要

synchronized 是 Java 最经典的并发关键字,用于保证原子性和可见性。本文将系统介绍 synchronized 的三种使用方式,以及其在 JVM 层面的实现机制(对象头、锁升级、monitorenter/monitorexit 指令),带你从应用到原理全面理解这一核心同步工具。


正文

一、为什么需要 synchronized?

在并发编程中,多个线程同时访问共享资源可能导致:

  • 数据竞争:变量更新丢失;
  • 可见性问题:一个线程更新了值,另一个线程仍读取旧数据;
  • 有序性问题:指令重排导致逻辑异常。

synchronized 的作用就是提供一种 互斥锁机制,保证同一时间只有一个线程能进入临界区,从而解决上述问题。


二、synchronized 的三种使用方式

1. 修饰实例方法
java 复制代码
public synchronized void increment() {
    count++;
}
  • 锁对象:当前实例(this)。
  • 适用场景:保护实例字段,避免多个线程同时修改。
2. 修饰静态方法
java 复制代码
public static synchronized void staticIncrement() {
    counter++;
}
  • 锁对象:当前类的 Class 对象(即 Class<类名>)。
  • 适用场景:保护静态字段,避免类级别的数据竞争。
3. 修饰代码块
java 复制代码
public void add() {
    synchronized (lock) {
        count++;
    }
}
  • 锁对象:显式指定的对象引用。
  • 适用场景:锁粒度可控,能减少竞争范围,提高性能。

总结

  • 实例方法 锁住对象实例;
  • 静态方法 锁住类对象;
  • 代码块 锁住指定对象。

三、synchronized 的底层原理

synchronized 在 JVM 中是通过 对象头(Object Header)+ Monitor(监视器锁) 来实现的。

1. 对象头与 Mark Word

在 HotSpot JVM 中,每个对象头(Object Header)包含:

  • Mark Word:存储锁状态、哈希码、GC 分代年龄等;
  • Klass Pointer:指向类的元数据。

锁相关的核心信息都在 Mark Word 中,比如锁标志位(00、01、10、11 对应不同状态)。

2. monitorenter & monitorexit 指令

编译器在同步代码块前后插入两条字节码指令:

  • monitorenter:尝试获取锁;
  • monitorexit:释放锁。

一个线程在执行 monitorenter 时,如果锁已被占用,就会阻塞直到获取成功。

3. 锁的升级过程(优化机制)

HotSpot 对 synchronized 进行了多种优化,避免频繁进入内核态:

  • 偏向锁(Biased Lock):默认锁偏向第一个获取它的线程,后续无竞争时无需加锁操作;
  • 轻量级锁(Lightweight Lock):当多个线程尝试获取锁时,利用 CAS 在用户态竞争;
  • 重量级锁(Heavyweight Lock):CAS 自旋失败或冲突严重时,升级为 OS 层面的互斥锁,线程进入阻塞状态。

这种 锁升级(无锁 → 偏向锁 → 轻量级锁 → 重量级锁) 的设计,大幅提高了 synchronized 的性能。


四、synchronized 的特性

  1. 可重入性
    同一线程可以多次获取同一个锁,不会死锁。
java 复制代码
public synchronized void methodA() {
    methodB(); // 同一线程可再次进入
}
public synchronized void methodB() {}
  1. 可见性
    synchronized 内部会在 释放锁时刷新主存、获取锁时读取主存,保证线程间数据可见性。
  2. 互斥性
    同一时刻,最多只有一个线程能进入临界区。

五、工程实践中的使用建议

  1. 缩小锁粒度
    只在必要的临界区加锁,避免长时间持有锁,提升并发度。
  2. 选择合适的锁对象
  • 不要随便用 String 常量或全局对象作为锁,容易引发意外竞争;
  • 建议使用 private final Object lock = new Object(); 作为显式锁对象。
  1. 避免死锁
    在多个锁嵌套场景下,保持一致的加锁顺序。
  2. 适度考虑替代方案
    在高并发场景下,可以使用 ReentrantLockStampedLockReadWriteLock 等并发工具类,获得更灵活的功能(如中断、超时、公平性)。

六、总结

synchronized 是 Java 并发的基石,它通过 对象头 + Monitor 实现锁机制,并结合 偏向锁、轻量级锁、重量级锁 提升性能。

三种用法分别对应 对象锁、类锁、自定义锁对象,开发时需要注意锁粒度、锁对象选择以及死锁风险。

相关推荐
豐儀麟阁贵19 分钟前
2.6 代码注释与编码规
java·开发语言
程序员三明治20 分钟前
【Mybatis从入门到入土】ResultMap映射、多表查询与缓存机制全解析
java·sql·缓存·mybatis·resultmap·缓存机制·多表查询
间彧25 分钟前
Java transient关键字详解与项目实战
后端
华仔啊26 分钟前
Java 重试机制没写对,线上很容易出问题!这份生产级方案请收好
java·后端
你不是我我28 分钟前
【Java 开发日记】什么是线程池?它的工作原理?
java·开发语言
Seven9730 分钟前
剑指offer-35、数组中的逆序对
java·leetcode
梵得儿SHI44 分钟前
Java 反射机制深度解析:从运行时 “解剖” 类的底层逻辑
java·开发语言·反射·反射机制·private·类成员·反射的三大核心功能
CodeSheep1 小时前
大家有没有发现一个奇特现象:你能在一个公司工作 12 年以上,无论你多忠诚多卖力,一旦公司赚的少了,那你就成了“眼中钉肉中刺”
前端·后端·程序员
豆沙沙包?1 小时前
2025年--Lc188--931. 下降路径最小和(多维动态规划,矩阵)--Java版
java·矩阵·动态规划
JAVA学习通1 小时前
Spring AI 1.0 GA 深度解析:Java生态的AI革命已来
java·人工智能·spring·springai