1. 同步问题的本质与解决方案
在多线程编程中,最核心的挑战就是如何解决资源竞争问题。想象一下多个线程同时操作同一个银行账户的场景:如果没有适当的控制机制,存款和取款操作交叉执行就可能导致余额计算错误。这就是典型的竞态条件(Race Condition)问题。
Java 语言从设计之初就考虑到了线程安全问题,提供了多种同步机制。其中 synchronized 关键字是最基础、最常用的线程同步工具。它就像会议室的门锁——当一个人在里面开会时,其他人必须等待锁释放才能进入。
与其它同步机制相比,synchronized 有三大特点:
- 内置语言特性,无需额外导入类库
- 自动管理锁的获取和释放
- 可作用于方法或代码块,使用灵活
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. synchronized 的实现原理
2.1 JVM 层面的实现机制
在 JVM 中,每个对象都有一个内置锁(monitor lock),也称为监视器锁。当线程进入 synchronized 方法或代码块时,会自动获取这个锁;退出时自动释放。这个机制是通过 monitorenter 和 monitorexit 这两个字节码指令实现的。
对象头中的 Mark Word 存储了锁状态信息,包括:
- 锁标志位(2bit)
- 是否偏向锁(1bit)
- 锁记录指针
- 重量级锁指针
2.2 锁升级过程解析
为了提高性能,JVM 采用了锁升级策略:
- 无锁状态:对象刚创建时的初始状态
- 偏向锁:当第一个线程访问时,会记录线程ID,后续该线程可以直接进入
- 轻量级锁:当有第二个线程尝试获取锁时,升级为CAS自旋锁
- 重量级锁:当自旋超过一定次数(默认10次),升级为操作系统层面的互斥锁
注意:锁升级是不可逆的过程,一旦升级为重量级锁就无法降级
3. synchronized 的四种使用方式
3.1 实例方法同步
java复制public synchronized void transfer(Account target, int amount) {
this.balance -= amount;
target.balance += amount;
}
这种写法等价于:
java复制pu
