一、整体关系框架
Java 内存模型(JMM)是并发编程的底层规则,定义了多线程环境下共享变量的访问方式。 volatile、synchronized 是 JMM 规则的具体实现手段,而 AQS 和 LockSupport 是基于 JMM 和这些关键字构建的高并发工具。 以下是它们的协作关系:
JMM(规则层)
├── volatile(可见性、有序性)
├── synchronized(原子性、可见性、有序性)
├── AQS(基于 volatile 和 CAS 的同步框架)
└── LockSupport(基于 JMM 的线程阻塞与唤醒)
二、JMM 的核心规则
JMM 通过以下规则约束多线程行为:
- 可见性:线程对共享变量的修改对其他线程可见。
- 有序性:禁止指令重排序(通过内存屏障)。
- 原子性:特定操作(如锁、CAS)的不可分割性。
三、volatile 与 JMM
1. 作用
- 可见性:强制读写直接操作主内存。
- 有序性:插入内存屏障禁止指令重排序。
2. 实现原理
- 写操作:在写后插入
StoreStore和StoreLoad屏障。 - 读操作:在读前插入
LoadLoad和LoadStore屏障。
3. 典型应用
- 状态标志位(如
volatile boolean flag)。 - 双重检查锁定(DCL 单例模式)。
四、synchronized 与 JMM
1. 作用
- 原子性:同步代码块的互斥执行。
- 可见性:锁释放时强制刷新工作内存到主内存。
- 有序性:同步块内禁止指令重排序。
2. 内存语义
- 加锁:清空工作内存,从主内存加载共享变量。
- 解锁:将工作内存的修改刷新到主内存。
3. 典型应用
- 保护临界区(如计数器递增)。
- 实现互斥锁(如
ReentrantLock的底层依赖)。
五、AQS 与 JMM
1. 核心依赖
- volatile state:AQS 通过
volatile int state管理同步状态,依赖 JMM 的可见性规则。 - CAS 操作:通过
Unsafe.compareAndSwapXXX实现原子性状态更新。
2. 同步机制
-
等待队列:使用 CLH 队列管理阻塞线程,依赖 LockSupport 的
park()和unpark()。 -
锁获取与释放:
// AQS 中的模板方法 protected boolean tryAcquire(int arg) { /* 依赖 CAS 和 volatile state */ } protected boolean tryRelease(int arg) { /* 修改 state 并唤醒后继线程 */ }
3. 典型应用
ReentrantLock、Semaphore、CountDownLatch的底层实现。
六、LockSupport 与 JMM
1. 作用
- 线程阻塞与唤醒:提供
park()和unpark()的底层支持。 - 精准控制:可唤醒指定线程,避免
notify()的随机性。
2. 实现依赖
- 许可证机制:通过原子变量管理线程的阻塞状态。
- happens-before 规则:
unpark()操作对park()的可见性保证。
3. 典型应用
- AQS 的等待队列管理。
- 自定义线程协作(如替代
wait()/notify())。
七、协作关系示例
1. ReentrantLock 的工作流程
-
加锁:
- 通过 CAS 修改
volatile state(原子性、可见性)。 - 若失败,线程加入 AQS 队列并调用
LockSupport.park()阻塞(依赖 JMM 的可见性保证)。
- 通过 CAS 修改
-
解锁:
- 修改
volatile state,唤醒队列中的下一个线程(LockSupport.unpark())。
- 修改
2. 双重检查锁定(DCL)
public class Singleton {
private static volatile Singleton instance; // 依赖 volatile 的可见性与有序性
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) { // 依赖 synchronized 的原子性
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
- volatile:禁止指令重排序(防止返回未初始化对象)。
- synchronized:保证实例化代码的原子性。
八、对比与选择
| 组件 | 解决的问题 | 适用场景 | 性能特点 |
|---|---|---|---|
| volatile | 可见性、有序性 | 状态标志、DCL 单例 | 轻量级,无锁 |
| synchronized | 原子性、可见性、有序性 | 临界区保护、简单同步 | 重量级,JVM 优化后性能提升 |
| AQS | 复杂同步需求 | 自定义锁、信号量、栅栏 | 灵活,支持公平/非公平锁 |
| LockSupport | 精准线程阻塞/唤醒 | AQS 队列管理、替代 wait/notify | 底层控制,无锁 |
九、总结
1. 层级关系
- JMM:定义内存访问规则(可见性、有序性、原子性)。
- volatile/synchronized:基于 JMM 的关键字实现。
- AQS/LockSupport:基于 JMM 和关键字的高并发工具。
2. 协作逻辑
- JMM 是基石:所有并发工具的行为均遵循其规则。
- volatile 和 synchronized 是基础工具:直接解决可见性、有序性、原子性问题。
- AQS 和 LockSupport 是高级工具:利用前者构建复杂同步机制。
3. 开发建议
- 简单同步:优先使用
synchronized或volatile。 - 复杂需求:使用 AQS 构建自定义同步器(如限流器、分布式锁)。
- 精准控制:用
LockSupport替代wait()/notify()。
通过理解这些组件的协作关系,开发者可以更高效地设计线程安全程序,避免内存可见性、指令重排序等并发陷阱。