volatile核心作用是保证可见性和禁止指令重排序:每次读写均强制主内存操作,且插入内存屏障约束顺序;但不保证原子性,故适用于状态标志等单次读写场景,不可用于count++等复合操作。

Java中volatile关键字核心就干两件事:让变量修改对其他线程「立刻可见」,同时「禁止指令重排序」。它不加锁、不开销大,但也不是万能的——不能替代synchronized来保证原子性。
volatile解决的是“读不到最新值”的问题
多核CPU下,每个线程可能把变量缓存在自己核心的高速缓存里,而不是每次都去主内存读写。一个线程改了值,只刷到了自己的缓存,别的线程还在读旧缓存,就“看不见”变化——这就是可见性问题。
加了volatile后,每次写操作强制写回主内存;每次读操作强制从主内存读取。相当于绕过了本地缓存,所有线程看到的永远是同一份最新数据。
- 典型场景:用作状态标志,比如
volatile boolean running = true;,另一个线程设为false,循环线程能立刻感知并退出 - 注意:仅适用于“单次读”或“单次写”,比如
flag = true、count++就不行——后者是“读-改-写”三步,不是原子操作
volatile还能防止编译器和CPU乱序执行
为了性能,编译器或处理器可能调整语句顺序(只要单线程结果不变)。但在多线程里,这种重排可能导致逻辑错乱。比如双重检查锁定(DCL)单例中,对象构造还没完成,引用就被其他线程看到了。
立即学习“Java免费学习笔记(深入)”;
volatile会在读写前后插入内存屏障(Memory Barrier),约束指令顺序:
- 写volatile变量前的所有操作,不能被重排到写之后
- 读volatile变量后的所有操作,不能被重排到读之前
- 从而保证“先初始化、再赋值、再被读到”的逻辑链不被破坏
volatile和synchronized的区别很关键
volatile只提供可见性和有序性,不提供原子性;synchronized三者都管,还带互斥能力。
- 比如
volatile int counter = 0;,多个线程执行counter++,结果大概率小于预期——因为自增不是原子的 - 而
synchronized块内做同样操作,就能保证正确 - 所以volatile适合“纯通知”类场景,不适合“需要复合操作”的共享计数、累加等
基本上就这些。用对地方很轻量,滥用反而掩盖并发bug。










