Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

  • Java集合

  • Java并发

    • Java并发概述
    • 线程与进程
    • Thread类与线程生命周期
    • 线程创建与任务模型
    • 线程安全
    • synchronized关键字
      • 1. 三种用法
      • 2. 锁对象
      • 3. Monitor 模型
      • 4. 可重入性
      • 5. synchronized 的内存语义
      • 6. 字节码视角
      • 7. 锁粒度
      • 8. 不要锁字符串和包装类
      • 9. synchronized 与 ReentrantLock
      • 10. 死锁风险
      • Tips 快问快答
    • volatile关键字
    • Java内存模型(JMM)
    • 线程间通信
    • 线程池
    • 并发工具类
    • 原子操作类Atomic
    • 并发锁
    • 并发容器
    • ConcurrentHashMap
    • BlockingQueue
    • CopyOnWriteArrayList
    • ThreadLocal
    • Fork/Join框架
    • ScheduledThreadPoolExecutor
    • CompletableFuture
    • 虚拟线程
    • 死锁活锁与线程问题排查
    • 并发编程最佳实践
  • Java IO

  • JVM

  • Java
  • Java并发
Wray
2026-06-24
目录

synchronized关键字

synchronized 是 Java 最基础的互斥同步机制。它基于对象监视器 Monitor 实现,可以修饰实例方法、静态方法和代码块。

它解决的不只是“同一时间只有一个线程执行”,还包含可见性和有序性语义。

# 1. 三种用法

修饰实例方法:

public synchronized void increment() {
    count++;
}

锁对象是当前实例 this。

修饰静态方法:

public static synchronized void refresh() {
}

锁对象是当前类的 Class 对象。

修饰代码块:

synchronized (lock) {
    count++;
}

锁对象是括号里的对象。

# 2. 锁对象

写法 锁对象
synchronized instanceMethod this
synchronized staticMethod Class 对象
synchronized(lock) 指定的 lock 对象

示意:

线程 A -> synchronized(lock) -> 持有 monitor
线程 B -> synchronized(lock) -> 等待
线程 C -> synchronized(otherLock) -> 不受影响

锁的是对象,不是代码。两个线程只有竞争同一个锁对象时才互斥。

# 3. Monitor 模型

每个 Java 对象都可以关联一个 Monitor。

Object
  │
  ▼
Monitor
├─ Owner:当前持锁线程
├─ EntryList:等待进入锁的线程
└─ WaitSet:调用 wait 后等待通知的线程

进入 synchronized:

尝试获取 monitor
  │
  ├─ 成功:成为 Owner,执行临界区
  └─ 失败:进入 EntryList,线程 BLOCKED

退出 synchronized 时释放 monitor,其他等待线程再竞争。

# 4. 可重入性

synchronized 是可重入锁。同一个线程已经持有某个锁时,可以再次获取它。

public synchronized void a() {
    b();
}

public synchronized void b() {
}

执行过程:

线程 T 获取 this 锁,进入 a
  │
  ▼
调用 b,再次获取 this 锁
  │
  ▼
重入次数 +1

可重入避免了同一线程调用自身同步方法时死锁。

# 5. synchronized 的内存语义

进入和退出 synchronized 会建立 happens-before 关系。

线程 A:
synchronized(lock) {
    shared = 1;
}

线程 B:
synchronized(lock) {
    read shared;
}

规则:

线程 A 释放 lock
happens-before
线程 B 随后获取同一个 lock

因此 B 能看到 A 在释放锁前对共享变量的修改。

# 6. 字节码视角

同步代码块通常对应:

monitorenter
  临界区
monitorexit

异常时也必须释放锁,因此编译器会生成异常路径上的 monitorexit。

同步方法则通过方法访问标志表达,JVM 在方法调用和返回时处理 monitor。

# 7. 锁粒度

锁粒度过大:

public synchronized void process() {
    readFromRemote();
    updateState();
    writeLog();
}

如果远程调用很慢,其他线程长时间等待。

优化思路:

Data data = readFromRemote();
synchronized (lock) {
    updateState(data);
}
writeLog();

但不能为了缩小锁范围破坏共享状态一致性。锁要覆盖完整的不变量维护过程。

# 8. 不要锁字符串和包装类

不推荐:

synchronized ("LOCK") {
}

字符串字面量会进入常量池,可能被其他代码共享。

也不要锁可能被缓存的包装类:

synchronized (Integer.valueOf(1)) {
}

推荐:

private final Object lock = new Object();

# 9. synchronized 与 ReentrantLock

对比项 synchronized ReentrantLock
使用方式 关键字 API
释放锁 自动释放 必须手动 unlock
可重入 支持 支持
可中断获取 不支持 支持
尝试获取 不支持 支持 tryLock
公平锁 不支持配置 支持
条件队列 一个 WaitSet 多个 Condition

简单互斥优先 synchronized;需要可中断、超时、公平锁、多条件队列时考虑 ReentrantLock。

# 10. 死锁风险

synchronized (lockA) {
    synchronized (lockB) {
    }
}

如果另一个线程反过来先拿 lockB 再拿 lockA,可能死锁。

避免策略:

  • 固定锁顺序。
  • 减少嵌套锁。
  • 使用 tryLock 加超时。
  • 避免锁内调用外部未知代码。

# Tips 快问快答

Q:synchronized 锁的是代码还是对象? A:锁的是对象。多个线程竞争同一个锁对象时才互斥。

Q:实例同步方法锁什么? A:锁当前实例 this。

Q:静态同步方法锁什么? A:锁当前类的 Class 对象。

Q:synchronized 是可重入的吗? A:是,同一线程可重复获取同一把锁。

Q:synchronized 能保证可见性吗? A:能。释放锁 happens-before 后续获取同一锁。

Q:为什么不要锁字符串? A:字符串常量池可能导致锁对象被意外共享。

Q:锁范围越小越好吗? A:不一定,要保证共享状态的不变量被完整保护。

Q:什么时候用 ReentrantLock? A:需要 tryLock、可中断、公平锁或多个条件队列时。

上次更新: 2026/06/24, 17:22:59
线程安全
volatile关键字

← 线程安全 volatile关键字→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式