本文目录导读:

- 经典案例:线程可见性问题
- 双重检查锁(Double-Checked Locking)场景
- 计数器案例(展示volatile不保证原子性)
- volatile应用场景总结
- volatile的三大特性总结
- 完整的生产案例
- 面试必问总结
下面我来详细讲解Java中volatile关键字的经典案例和原理。
经典案例:线程可见性问题
错误示例(没有volatile)
public class NoVolatileExample {
// 没有volatile,线程间不可见
private static boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread reader = new Thread(() -> {
System.out.println("Reader线程开始执行...");
while (!flag) {
// 空循环等待flag变为true
}
System.out.println("Reader线程检测到flag变化,退出循环");
});
Thread writer = new Thread(() -> {
System.out.println("Writer线程开始执行...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("Writer线程已将flag设置为true");
});
reader.start();
writer.start();
reader.join();
writer.join();
System.out.println("程序执行完毕");
}
}
运行结果:Reader线程可能会永远停不下来,因为flag的变化对Reader线程不可见(JIT编译优化)。
正确示例(使用volatile)
public class VolatileExample {
// 使用volatile保证可见性
private static volatile boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread reader = new Thread(() -> {
System.out.println("Reader线程开始执行...");
while (!flag) {
// 空循环等待
}
System.out.println("Reader线程检测到flag变化,退出循环");
});
Thread writer = new Thread(() -> {
System.out.println("Writer线程开始执行...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("Writer线程已将flag设置为true");
});
reader.start();
writer.start();
reader.join();
writer.join();
System.out.println("程序执行完毕");
}
}
运行结果:Reader线程能及时感知到flag的变化,正常退出。
双重检查锁(Double-Checked Locking)场景
public class Singleton {
// volatile防止指令重排序
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (Singleton.class) {
if (instance == null) { // 第二次检查
instance = new Singleton(); // 创建实例
}
}
}
return instance;
}
}
为什么需要volatile?
new Singleton() 可以分解为以下三个步骤:
- 分配内存空间
- 初始化对象
- 将内存地址赋值给引用
编译器可能将其重排序为:
- 分配内存空间
- 将内存地址赋值给引用(未初始化)
- 初始化对象
如果线程A执行了步骤1和2(未初始化),线程B进来看到instance != null,直接返回了未初始化的对象,导致错误。
用volatile可以禁止指令重排序,确保先初始化再赋值。
计数器案例(展示volatile不保证原子性)
public class VolatileCounter {
private static volatile int count = 0;
public static void main(String[] args) throws InterruptedException {
// 创建100个线程同时增加计数
for (int i = 0; i < 100; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
count++; // 不是原子操作!
}
}).start();
}
Thread.sleep(3000);
// 期望结果是100000,但实际可能不是
System.out.println("最终count值: " + count);
}
}
分析:count++ 有三个步骤:
- 读取count值
- 加1
- 写回count
volatile只保证可见性,不保证原子性,所以最终结果可能小于100000。
解决方案(使用synchronized或原子类)
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicCounter {
private static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
count.incrementAndGet(); // 原子操作
}
}).start();
}
Thread.sleep(3000);
System.out.println("最终count值: " + count.get()); // 输出100000
}
}
volatile应用场景总结
适用场景
public class VolatileUseCase {
// 场景1:状态标志位
private volatile boolean shutdown = false;
// 场景2:单次状态发布
private volatile boolean initialized = false;
// 场景3:配置值更新
private volatile String configValue = "default";
public void shutdown() {
shutdown = true; // 写入可见性
}
public void doWork() {
while (!shutdown) {
// 执行工作
}
}
// 场景4:安全发布不可变对象(配合final)
private static class ImmutableObject {
private final int value;
private final String name;
ImmutableObject(int value, String name) {
this.value = value;
this.name = name;
}
}
private volatile ImmutableObject snapshot;
public void updateSnapshot(int value, String name) {
snapshot = new ImmutableObject(value, name); // 安全发布
}
public ImmutableObject getSnapshot() {
return snapshot;
}
}
volatile的三大特性总结
public class VolatileSummary {
// 1. 可见性:volatile变量的修改对其他线程立即可见
private volatile boolean visibleFlag;
// 2. 有序性:禁止指令重排序(添加内存屏障)
private volatile int orderValue;
// 3. volatile不保证原子性(不具备原子性)
private volatile int notAtomic = 0;
public void increment() {
notAtomic++; // 非原子操作
}
}
内存屏障详解
public class MemoryBarrier {
private int a;
private volatile boolean flag = false;
public void write() {
a = 1; // 普通写
flag = true; // volatile写,插入StoreStore屏障
// 确保a=1在flag=true之前完成
}
public void read() {
if (flag) { // volatile读,插入LoadLoad屏障
int temp = a; // 确保读取到最新的a值
}
}
}
完整的生产案例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class VolatileCompleteExample {
// 服务状态
private volatile boolean running = true;
// 当前任务数(用AtomicInteger保证原子性)
private final java.util.concurrent.atomic.AtomicInteger taskCount =
new java.util.concurrent.atomic.AtomicInteger(0);
// 配置信息(用volatile保证可见性)
private volatile TaskConfig config = new TaskConfig(5, "默认配置");
// 不可变配置对象
public static class TaskConfig {
private final int poolSize;
private final String name;
public TaskConfig(int poolSize, String name) {
this.poolSize = poolSize;
this.name = name;
}
public int getPoolSize() { return poolSize; }
public String getName() { return name; }
}
// 执行任务
public void process() {
ExecutorService executor = Executors.newFixedThreadPool(config.getPoolSize());
while (running && !Thread.currentThread().isInterrupted()) {
try {
taskCount.incrementAndGet();
executor.submit(() -> {
try {
System.out.println(Thread.currentThread().getName() +
" 执行任务: " + config.getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
taskCount.decrementAndGet();
}
});
Thread.sleep(200);
} catch (InterruptedException e) {
running = false;
Thread.currentThread().interrupt();
}
}
executor.shutdown();
System.out.println("服务停止,剩余任务数: " + taskCount.get());
}
// 停止服务
public void stop() {
running = false; // volatile可见性,立即通知其他线程停止
}
// 更新配置
public void updateConfig(int poolSize, String name) {
if (poolSize <= 0 || name == null || name.isEmpty()) {
throw new IllegalArgumentException("无效的配置参数");
}
config = new TaskConfig(poolSize, name); // volatile安全发布
System.out.println("配置已更新: " + config.getName());
}
public static void main(String[] args) throws InterruptedException {
VolatileCompleteExample example = new VolatileCompleteExample();
// 启动服务线程
Thread serviceThread = new Thread(example::process);
serviceThread.start();
// 模拟运行5秒后停止
Thread.sleep(5000);
example.updateConfig(10, "新配置");
Thread.sleep(2000);
example.stop();
serviceThread.join();
System.out.println("主程序执行完毕");
}
}
面试必问总结
volatile vs synchronized vs Atomic
| 特性 | volatile | synchronized | Atomic类 |
|---|---|---|---|
| 可见性 | |||
| 原子性 | ✅(单变量) | ||
| 有序性 | ✅(禁止重排序) | ||
| 性能 | 最高 | 较低(有锁) | 较高(CAS) |
| 使用场景 | 状态标志、单次发布 | 复合操作、临界区 | 计数器、累加器 |
什么时候该用volatile?
- 状态标志:简单的开关状态
- 单次发布:只读状态的安全发布
- 独立观察:多个变量相互独立,不涉及复合操作
什么时候不该用volatile?
- 需要保证复合操作的原子性(如
count++) - 操作依赖当前值(如
if(x) { ... }) - 需要互斥访问
volatile的实现原理:
// 伪代码展示volatile的内存屏障插入
public class MemoryBarrierExample {
int a = 1;
volatile boolean flag = false;
void write() {
a = 2; // 普通写
// 插入StoreStore屏障
flag = true; // volatile写
// 插入StoreLoad屏障
}
void read() {
// 插入LoadLoad屏障
if (flag) { // volatile读
int b = a; // 看到最最新的a值
}
// 插入LoadStore屏障
}
}
核心要点:
- 可见性:volatile变量的修改立即对其他线程可见(通过主内存)
- 有序性:禁止指令重排序(通过内存屏障)
- 不保证原子性:复合操作需要另外加锁或使用原子类
- 典型应用:双重检查锁、状态标志、安全发布不可变对象
性能影响:
- volatile读操作开销与普通读相近
- volatile写操作开销比普通写大(需要刷新到主存和使其他缓存失效)
- 但比synchronized的性能开销小得多(无锁操作)
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播