订阅更新

volatile能保证线程安全吗?——Java内存模型(JMM)详解

Java手册 第 17 题 约 5 分钟读完

本文目录
  1. 先说结论
  2. JMM核心模型
  3. volatile三个特性
  4. 为什么不保证原子性?
  5. happens-before规则
  6. volatile在大数据中的应用
  7. 内存屏障——volatile底层实现
  8. 面试高频追问
  9. 总结

先说结论

JMM定义了多线程访问共享变量的规则。每个线程有工作内存(CPU缓存),共享变量在主内存。volatile保证:① 可见性(修改立刻刷到主内存);② 有序性(禁止指令重排)。但不保证原子性——volatile int count; count++仍不安全。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

volatile是Java面试经典考点。答案是'不完全能'——保证可见性和有序性,不保证原子性。大数据中volatile用于状态标志位(Flink的isRunning),不能用于计数器(i++非原子)。理解volatile需要先理解JMM。

JMM核心模型

# 线程A工作内存  ←→  主内存  ←→  线程B工作内存
# 线程A改x=1,只更新自己的工作内存
# 线程B读x,从自己工作内存读到旧值0
# 这就是可见性问题
#
# volatile的作用:
# 写volatile:立刻刷新到主内存
# 读volatile:从主内存重新加载

volatile三个特性

特性含义volatile保证?示例
可见性修改对其他线程立刻可见保证volatile boolean isRunning
有序性禁止指令重排序保证双重检查锁单例
原子性操作不可被中断不保证count++不安全!

为什么不保证原子性?

// count++ = read + add + write 三步
// 线程A read=0, 线程B也read=0
// 两者都add写回1,最终1而不是2
 
// 正确做法:
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();  // CAS原子操作

happens-before规则

规则含义大数据场景
程序顺序同线程内代码顺序执行Flink算子内部有序
volatile写 hb 后续读状态标志位可见
锁unlock hb 后续locksynchronized内修改可见
线程启动start() hb 线程内操作创建Executor线程
传递性A hb B且B hb C则A hb C组合规则

volatile在大数据中的应用

// Flink SourceFunction停止标志
private volatile boolean isRunning = true;
public void run(SourceContext<Event> ctx) {
    while (isRunning) { ctx.collect(readNext()); }
}
public void cancel() { isRunning = false; }
 
// 双重检查锁单例
private static volatile RedisClient instance;
// new RedisClient()可能被重排为:分配内存+赋引用+初始化
// volatile禁止重排,保证其他线程不会读到半初始化的对象

内存屏障——volatile底层实现

volatile底层是CPU内存屏障指令。写volatile时在写前后插StoreStore/StoreLoad屏障,保证写入刷到主内存;读volatile时插LoadLoad/LoadStore屏障,保证从主内存读最新值。保证了可见性和有序性,但不保证原子性。

面试高频追问

追问一:volatile和synchronized区别?

volatile保证可见性+有序性不保证原子性,只修饰变量,轻量。synchronized保证三者,修饰方法和代码块,重量。简单标志用volatile,复合操作用synchronized。

追问二:volatile性能开销?

比普通变量大但比synchronized小很多。低频标志位用volatile几乎无感知,高频计数器用LongAdder。

追问三:final字段有happens-before语义吗?

有。构造函数中final字段写 hb 任何线程读取该字段。所有字段都final的不可变对象天然线程安全,不需volatile/synchronized。RDD设计成不可变的好处之一。

总结

JMM和volatile面试讲三层:① JMM模型(工作内存+主内存,可见性问题根源);② volatile三特性(可见+有序,不保证原子,count++不安全);③ happens-before规则。能讲出Flink isRunning标志和双重检查锁应用,面试官觉得你理解了本质。

下一篇聊Java 8+新特性:Lambda/Stream/Optional/CompletableFuture在大数据中的应用。

你们代码里用volatile了吗?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器