java内存模型(jmm)是规范线程读写共享变量的规则,核心解决可见性、原子性、有序性问题;可见性指线程修改后其他线程能否及时看到,靠volatile/synchronized保证;原子性指操作不可拆分,需synchronized或atomicinteger等保障。

Java 内存模型(JMM)不是物理内存结构,而是一套规范线程如何读写共享变量的规则。它的核心作用是解决多线程环境下因 CPU 缓存、指令重排序等硬件优化带来的三大问题:可见性、原子性、有序性。其中,可见性与原子性是最常被混淆也最易出错的两个点。
可见性:一个线程改了,另一个线程能不能“立刻看到”
可见性问题的本质是线程工作内存和主内存之间的同步延迟。每个线程有自己的工作内存,它只操作变量的副本;修改后若不强制刷回主内存,其他线程的工作内存可能一直用着旧值——就像你改了文档保存,但同事打开的是本地缓存副本,看不到你的更新。
典型表现:
- 主线程把 running = false 写入主内存,但工作线程仍在自己的工作内存里循环读取旧的 true
- 没有同步手段时,即使变量已被修改,另一线程也可能永远“看不见”
保证可见性的常用方式:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- volatile:写 volatile 变量时,JMM 要求立即将值写回主内存;读该变量时,必须从主内存重新加载。同时禁止相关指令重排序
- synchronized:进入同步块前,清空工作内存中该锁保护的变量副本;退出时,将修改强制写回主内存
- Lock 接口实现类(如 ReentrantLock):语义同 synchronized,同样具备“释放锁前刷新主内存”的保障
原子性:操作是否“不可拆分”
原子性关注的是执行过程是否会被中断。JMM 仅保证基本数据类型(int、boolean、short、char、byte、float)的读写是原子的;但 long 和 double 在 32 位 JVM 上可能被拆成两次 32 位写入,存在“半个值被读到”的风险。
更常见的是复合操作的非原子性,比如 i++ 实际包含三步:读取 i → 计算 i+1 → 写回 i。多个线程交错执行这三步,就会丢失更新。
保障原子性的主要手段:
- synchronized:用互斥锁把非原子操作包裹成临界区,确保同一时刻只有一个线程执行
- java.util.concurrent.atomic 包下的原子类(如 AtomicInteger):基于 CAS(Compare-And-Swap)指令,在硬件层面实现无锁原子更新
- volatile + CAS 或其他同步逻辑:单独用 volatile 不能保证 i++ 原子性,但它能配合 CAS 构建原子操作的基础条件(如提供最新值用于比较)
可见性与原子性不是一回事,也不能互相替代
很多人误以为加了 volatile 就“线程安全了”,其实不然:
- volatile 能保证可见性,也能禁止重排序,但不保证原子性。对 volatile int count 的自增操作仍会出错
- synchronized 既保证可见性,又保证原子性,因为它强制进出时同步变量状态
- AtomicInteger 的 getAndIncrement() 方法内部用 volatile 读取当前值 + CAS 尝试写入,是可见性与原子性协同工作的典型设计
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










