题目
解释Java内存模型中的可见性问题及volatile的作用
信息
- 类型:问答
- 难度:⭐
考点
主内存与工作内存,可见性问题,volatile关键字
快速回答
可见性问题指一个线程修改共享变量后,其他线程无法立即看到最新值。解决方案:
- 使用
volatile关键字修饰变量 - 保证修改后的值立即同步到主内存
- 强制其他线程从主内存重新读取该变量
原理说明
Java内存模型(JMM)规定:
- 所有变量存储在主内存中
- 每个线程有独立的工作内存,保存主内存变量的副本
- 线程直接操作工作内存副本,导致多线程下可能出现可见性问题
代码示例
public class VisibilityDemo {
// 无volatile修饰可能导致问题
private static /*volatile*/ boolean flag = true;
public static void main(String[] args) {
new Thread(() -> {
while (flag) { // 可能永远读取旧值
// 空循环
}
System.out.println("线程停止");
}).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = false; // 主线程修改
System.out.println("flag已设置为false");
}
}问题分析
- 现象:子线程可能无法感知
flag变为false,导致死循环 - 原因:工作内存未刷新主内存修改
- 解决方案:添加
volatile关键字:private static volatile boolean flag = true;
volatile工作原理
- 写操作:立即刷新到主内存
- 读操作:直接从主内存读取
- 内存屏障:禁止指令重排序优化
最佳实践
- 对多线程共享的状态标志使用
volatile - 适用场景:单写多读、状态开关等简单同步
- 不适用场景:需要原子性操作时(如
i++)
常见错误
- 误认为所有变量修改都自动可见
- 在需要原子操作时仅依赖
volatile - 过度使用导致性能下降
扩展知识
- synchronized:同步块内变量修改自动刷新主内存
- final变量:初始化后保证可见性
- happens-before原则:JMM的核心规则