Java volatile 关键字详解
概述
volatile 是 Java 中用于修饰变量的关键字,它提供了一种轻量级的线程间通信机制。与 synchronized 相比,volatile 不会引起线程上下文切换和调度,因此性能开销更小。不过它的同步能力有限,使用不当容易产生线程安全问题。
核心特性
1. 可见性保证(Visibility)
当某个线程修改 volatile 变量的值时,该值会立即被强制刷新到主内存。其他线程读取该变量时,会从主内存重新加载最新值,而不是使用本地线程缓存。这有效解决了多线程环境下因 CPU 缓存导致的数据不一致问题。
2. 有序性保证(Ordering)
volatile 禁止编译器和处理器对读写操作进行指令重排序。具体来说:
volatile写操作之前的任何读写操作不会被重排序到写之后。volatile读操作之后的任何读写操作不会被重排序到读之前。
这建立了 happens-before 关系,确保多线程间的操作顺序可见性。
3. 不保证原子性(Non-Atomicity)
这是最容易踩坑的地方。volatile 无法保证复合操作的原子性,比如 i++。因为复合操作由多个步骤组成,中间可能被其他线程中断。
内存语义
理解 volatile 的底层实现有助于更好地使用它。它通过内存屏障来保证语义。
volatile 写操作的内存屏障
[普通写/读操作] → [StoreStore 屏障] → [volatile 写] → [StoreLoad 屏障]
volatile 读操作的内存屏障
[volatile 读] → [LoadLoad 屏障] → [LoadStore 屏障] → [普通写/读操作]
内存屏障的作用:
- StoreStore 屏障:确保 volatile 写之前的普通写操作已刷新到主内存。
- StoreLoad 屏障:确保 volatile 写完成后,后续的读操作能看到所有之前的写入。
- LoadLoad 屏障:确保 volatile 读之后的操作不会被重排序到读之前。
- LoadStore 屏障:确保 volatile 读之后的写操作不会被重排序到读之前。
经典应用场景
1. 状态标志(最常用)
public class ShutdownHandler {
private volatile ;
{
shutdownRequested = ;
}
{
(!shutdownRequested) {
}
}
}


