Java Volatile关键字
外观
简介[编辑 | 编辑源代码]
volatile是Java中的关键字,用于修饰变量,确保多线程环境下的可见性和有序性。它告诉JVM和编译器:该变量可能被多个线程同时访问,禁止进行某些优化(如缓存或指令重排序),从而保证线程安全。
核心特性[编辑 | 编辑源代码]
- 可见性:当一个线程修改volatile变量时,其他线程能立即看到最新值。
- 禁止指令重排序:编译器或处理器不会对volatile变量的操作与其他内存操作进行重排序。
为什么需要volatile?[编辑 | 编辑源代码]
在Java内存模型(JMM)中,每个线程有自己的工作内存(缓存),变量的修改可能不会立即同步到主内存。非volatile变量可能导致以下问题:
- 脏读:线程A修改了变量,但线程B读取到旧值。
- 指令重排序:代码执行顺序与编写顺序不一致,导致逻辑错误。
语法与示例[编辑 | 编辑源代码]
基本用法[编辑 | 编辑源代码]
public class VolatileExample {
private volatile boolean flag = false;
public void start() {
new Thread(() -> {
while (!flag) {
// 等待flag变为true
}
System.out.println("Flag is now true");
}).start();
new Thread(() -> {
try {
Thread.sleep(1000); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true; // 修改volatile变量
System.out.println("Flag set to true");
}).start();
}
public static void main(String[] args) {
new VolatileExample().start();
}
}
输出示例:
Flag set to true Flag is now true
非volatile的风险[编辑 | 编辑源代码]
如果将上述代码中的`volatile`去掉,可能因可见性问题导致第一个线程陷入死循环。
底层原理[编辑 | 编辑源代码]
volatile通过以下机制实现: 1. 内存屏障(Memory Barrier):插入特殊指令阻止重排序。 2. 缓存一致性协议(如MESI):强制同步CPU缓存与主内存。
实际应用场景[编辑 | 编辑源代码]
状态标志[编辑 | 编辑源代码]
class TaskRunner {
private volatile boolean running = true;
public void stop() {
running = false;
}
public void run() {
while (running) {
// 执行任务
}
}
}
单例模式(双重检查锁定)[编辑 | 编辑源代码]
class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
volatile的局限性[编辑 | 编辑源代码]
- 不保证原子性:复合操作(如i++)仍需同步。
- 依赖场景:仅适用于简单状态控制,复杂逻辑需用`synchronized`或`java.util.concurrent`工具。
常见问题[编辑 | 编辑源代码]
volatile vs synchronized[编辑 | 编辑源代码]
特性 | volatile | synchronized |
---|---|---|
可见性 | ✔️ | ✔️ |
原子性 | ❌ | ✔️ |
互斥性 | ❌ | ✔️ |
性能影响[编辑 | 编辑源代码]
volatile的读写比普通变量稍慢(因内存屏障),但远轻于`synchronized`。
总结[编辑 | 编辑源代码]
- 使用场景:单线程写多线程读、状态标志、双重检查锁定。
- 避免过度使用:不能替代真正的同步机制。