Java多线程变量不可见本质是线程操作工作内存副本,解决依赖JVM内存同步语义:volatile保证单变量可见性与禁止重排序,synchronized保障临界区整体可见性、原子性及互斥。

Java 多线程中变量“读写主内存不同步、修改不可见”,本质是各线程操作的是自己工作内存里的副本,而非实时与主内存交互。要避免不可见,关键不是手动控制读写主内存,而是借助 JVM 提供的内存同步语义——让读写行为自动触发主内存同步。核心手段有两个:用 volatile 保证单变量可见性,用 synchronized(或 Lock)保障临界区整体可见性与互斥。
volatile 用于简单状态标志的可见性同步
适合仅需“通知”类场景,比如开关信号、运行标志、初始化完成标记。
- 被 volatile 修饰的变量,每次读都强制从主内存加载最新值,每次写都立即刷新到主内存
- 它禁止编译器和处理器对该变量的读写进行重排序,确保操作顺序符合代码逻辑
- 注意:volatile 不保证复合操作原子性。例如
count++(读-改-写三步)即使 count 是 volatile,仍可能出错 - 典型用法:
private static volatile boolean running = true;,一个线程设为 false,另一个线程 while 循环能立刻感知退出
synchronized 确保临界区内的所有共享变量都同步
适用于需要保护一段逻辑、多个变量协同更新,或必须保证原子性的场景。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 进入 synchronized 块前:线程清空工作内存中相关变量的缓存,强制从主内存重新加载最新值
- 退出 synchronized 块时:将工作内存中所有被修改的共享变量全部刷新回主内存
- 这形成“读-改-写”闭环,天然满足 happens-before 规则(unlock happens-before 后续 lock),其他线程下次进入同一把锁的临界区时,一定看到全部更新
- 不仅解决可见性,还提供互斥能力,防止并发修改导致数据错乱
别踩这些常见坑
看似同步,实则无效的做法要避开:
立即学习“Java免费学习笔记(深入)”;
- 只对写操作加 synchronized、读操作不加——读线程可能仍读到旧副本,破坏可见性闭环
- 用普通变量 + Thread.sleep() 或 while(true) 轮询——没有内存屏障,JVM 可能优化掉重复读,导致死循环
- volatile 修饰引用类型(如
volatile List<String> list)——只保证 list 引用本身可见,list 内部元素增删仍不安全 - 误以为 synchronized 锁对象不同就能同步变量——必须是同一把锁,才能触发 JMM 的内存同步协议
选哪个?看需求粒度
单个布尔/整型状态变更 → 优先 volatile,轻量高效;
涉及多个变量、含计算逻辑、需排他执行 → 必须 synchronized 或 ReentrantLock。

















