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 实现锁机制,并结合 偏向锁、轻量级锁、重量级锁 提升性能。

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

相关推荐
小安同学iter7 小时前
Spring Cloud Gateway 网关(五)
java·开发语言·spring cloud·微服务·gateway
码农小C8 小时前
idea2025.1.5安装+pj
java·开发语言·apache
yzx9910138 小时前
Java视觉跟踪入门:使用OpenCV实现实时对象追踪
java·开发语言·人工智能·opencv
ytadpole8 小时前
揭密设计模式:像搭乐高一样构建功能的装饰器模式
java
q567315238 小时前
Nim轻量级爬虫:异步高效+代理轮换防封
开发语言·后端·爬虫·typescript·scala
哈哈很哈哈9 小时前
Scala协变、逆变、上界/下界、隐式参数、隐式转换
开发语言·后端·scala
黄雄进9 小时前
Spring Ioc —— 集合类型的依赖注入
java·后端·spring
瓯雅爱分享9 小时前
Java提供高效后端支撑,Vue呈现直观交互界面,共同打造的MES管理系统,含完整可运行源码,实现生产计划、执行、追溯一站式管理,提升制造执行效率
java·mysql·vue·软件工程·源代码管理