深度理解 Java synchronized —— 从原理到实战


文章目录

  • [一、synchronized 的作用](#一、synchronized 的作用)
      • [`synchronized` 解决两个问题:](#synchronized 解决两个问题:)
  • [二、synchronized 的三种使用方式](#二、synchronized 的三种使用方式)
    • [✔ 1. 修饰实例方法(锁 ------ 当前对象 this)](#✔ 1. 修饰实例方法(锁 —— 当前对象 this))
    • [✔2. 修饰静态方法(锁 ------ 当前类的 Class 对象)](#✔2. 修饰静态方法(锁 —— 当前类的 Class 对象))
    • [✔3. 修饰代码块(锁 ------ 任意对象)](#✔3. 修饰代码块(锁 —— 任意对象))
  • [三、synchronized 的底层原理(Monitor 机制)](#三、synchronized 的底层原理(Monitor 机制))
    • [✔1. synchronized 基于对象监视器(Monitor)实现](#✔1. synchronized 基于对象监视器(Monitor)实现)
  • [四、锁的升级过程(JDK 6 后重要优化)](#四、锁的升级过程(JDK 6 后重要优化))
  • 五、可见性是如何保证的?
  • [六、synchronized 与 Reentrant(可重入性)](#六、synchronized 与 Reentrant(可重入性))
  • [七、synchronized 与 volatile 的区别(面试高频)](#七、synchronized 与 volatile 的区别(面试高频))
  • [八、synchronized 的优缺点](#八、synchronized 的优缺点)
  • [九、synchronized VS Lock(面试必考)](#九、synchronized VS Lock(面试必考))
  • 十、实战

一、synchronized 的作用

synchronized 是 Java 提供的最基础、最核心的线程同步机制,用来保证多线程环境下的互斥访问可见性

虽然简单易用,但其背后的锁原理(Monitor)、对象头(Mark Word)、锁升级(偏向锁→轻量级锁→重量级锁)等概念极其重要,也是面试高频考点。

synchronized 解决两个问题:

  1. 互斥性(Mutual Exclusion)
    保证同一时刻只有一个线程可以执行临界区代码。
  2. 可见性(Visibility)
    保证释放锁前对共享变量的修改对下一个获得锁的线程可见(类似 volatile 的效果)。

二、synchronized 的三种使用方式

✔ 1. 修饰实例方法(锁 ------ 当前对象 this)

java 复制代码
public synchronized void test() {
    // 临界区
}

等价于:

java 复制代码
public void test() {
    synchronized (this) {
        // 临界区
    }
}

特点:

  • 作用于:同一个对象实例
  • 多个线程访问不同对象时不会互斥

✔2. 修饰静态方法(锁 ------ 当前类的 Class 对象)

java 复制代码
public static synchronized void test() {
    // 临界区
}

等价于:

java 复制代码
synchronized (MyClass.class) {
    // 临界区
}

特点:

  • 锁住的是 类对象,所有实例共享一把锁

✔3. 修饰代码块(锁 ------ 任意对象)

java 复制代码
Object lock = new Object();

synchronized (lock) {
    // 临界区
}

特点:

  • 最灵活
  • 推荐在实际开发中优先使用
  • 可以对任何对象加锁(Object、String 等)

三、synchronized 的底层原理(Monitor 机制)

✔1. synchronized 基于对象监视器(Monitor)实现

Java 中,每一个对象都可以作为锁,因为:

  • 每个对象在 JVM 中都有一个 对象头(Object Header)
  • 对象头中包含锁状态(Mark Word)
  • synchronized 通过 Monitor(监视器锁)实现互斥

四、锁的升级过程(JDK 6 后重要优化)

Java 的锁不是一开始就用重量级锁,而是逐步升级,以提升性能。

锁类型 特点 适用场景
无锁 无竞争 单线程
偏向锁 无需 CAS,完全无竞争 同一线程反复进入
轻量级锁 使用 CAS,自旋 少量竞争
重量级锁 阻塞/唤醒,最慢 竞争激烈

⚠️注意事项:

  • 锁只能从低级到高级升级
  • 不会降级(重要)

五、可见性是如何保证的?

当一个线程释放锁时,JVM 会做两件事:

  1. 把工作内存的变量刷新到主内存(释放锁 → 写回)
  2. 获得锁的线程会从主内存重新读取变量

因此保证:

  • 前一个线程修改的数据对后一个线程可见

六、synchronized 与 Reentrant(可重入性)

synchronized可重入锁
同一线程可以多次获得同一把锁不会死锁。

java 复制代码
public synchronized void a() {
    b(); // 可以再次获得同一把锁
}

public synchronized void b() {
    // ...
}

七、synchronized 与 volatile 的区别(面试高频)

对比 synchronized volatile
可见性
原子性 有(加锁) 没有
是否阻塞 会阻塞 不阻塞
用途 多个操作的原子性 单变量读写
底层 Monitor、锁升级 内存屏障、禁止指令重排

volatile 解决可见性,synchronized 解决原子性 + 可见性。


八、synchronized 的优缺点

✔优点

  • 语法简单
  • JVM 层面保证,没有死锁风险(可重入)
  • 经过大量优化(锁消除、偏向锁)性能已大幅提升

✔缺点

  • 粒度不够灵活(无条件等待)
  • 性能比 Lock 略弱(尤其在高并发中)
  • 无法进行尝试锁 / 中断锁 / 超时锁 等操作

九、synchronized VS Lock(面试必考)

特性 synchronized Lock
锁的释放 自动释放 必须 unlock()
可中断
可尝试 ✔(tryLock)
公平锁
条件队列 ✔(Condition)
性能 被优化后差别不大 更灵活,高并发优势明显

十、实战

建议 1:优先使用 synchronized(JDK 8 性能已非常好)
建议 2:优先锁代码块,而不是锁整个方法
建议 3:锁对象要私有,避免被外部使用

java 复制代码
private final Object lock = new Object();

建议 4:避免锁住字符串常量(共享跨 ClassLoader)

java 复制代码
synchronized ("LOCK") {} // ❌ 千万不要这样写


参考资料

深入理解Java中synchronized三种使用方式:助您写出线程安全的代码-知乎

synchronized - 指南 - ljbguanli - 博客园

相关推荐
W_326001 分钟前
Python-OpenCV:库、环境搭建、图片与摄像头解析
开发语言·图像处理·python·opencv·机器学习
zhy295632 分钟前
在 QAIRT Genie SDK 上部署 Llama 3.2 1B 模型:从环境准备到 C++ 推理
开发语言·c++·llama
爱跳舞的烤冷面14 分钟前
自学嵌入式第N天(Linux篇——文件编程)
java·开发语言·前端
怪奇云呼军22 分钟前
闪电智能VoiceAgent 如何管理呼入、接听、桥接和挂断状态?
java·前端·网络·数据库·人工智能
Escalating_xu30 分钟前
【Linux】进程间通信:从匿名管道、FIFO 到共享内存、消息队列与信号量
java·linux·面试
IT机器猫1 小时前
RabbitMQ基础二
java·spring boot·分布式·spring cloud·log4j·rabbitmq·springamqp
caimouse1 小时前
ReactOS 图形系统分析(33):字体子系统 — font.c
c语言·开发语言·reactos
卷心菜的学习路1 小时前
基于 Spring Cloud Tencent 元数据路由实现个人开发泳道,告别频繁部署
java·spring cloud
cxr8281 小时前
HyperMind Lab M1 架构地基 Implementation Plan <二>
开发语言·人工智能·架构
特立独行的猫a1 小时前
Tauri v2的Rust应用 → HarmonyOS(鸿蒙 PC)移植30分钟速成指南
开发语言·rust·harmonyos·tauri·移植·鸿蒙pc