volatile 能保证 long/double 单次读写原子性,因 JVM 规范强制要求其操作不可分割;普通 long/double 在 32 位 JVM 中可能被拆为两次 32 位操作,导致“字撕裂”;volatile 还保障可见性与有序性,但不保证复合操作(如 counter++)原子性。

Java 中 volatile 能保证 long 和 double 的写入原子性,是因为 JVM 规范强制要求:对 volatile 修饰的 long 或 double 变量的读写操作必须是单次、不可分割的(即原子的),即使在 32 位 JVM 上也不例外。
为什么普通 long/double 可能非原子?
在早期 JVM(尤其是 32 位)中,long 和 double 占 64 位,而某些 CPU 架构一次只能处理 32 位数据。因此,对非 volatile 的 long 或 double 变量的写入,可能被拆成两个 32 位操作:先写高 32 位,再写低 32 位。如果此时另一个线程读取,就可能读到“高低位不一致”的中间状态(比如高 32 位是旧值、低 32 位是新值),造成数据错乱。
这种现象叫“word tearing”(字撕裂)。JVM 规范允许这种行为——但仅限于非 volatile、非 synchronized 的场景。
volatile 如何解决这个问题?
volatile 关键字向 JVM 发出明确语义:该变量的读写必须具备可见性和原子性。为此,JVM 必须确保:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 对
volatile long或volatile double的每次写操作,都是一次完整的 64 位写(哪怕底层硬件不支持,JVM 也要通过加锁、内存屏障或特殊指令模拟); - 对应读操作也必须一次性读取全部 64 位,不能分两次;
- 同时禁止编译器和处理器对该变量的读写进行重排序,保障有序性。
注意:仅限读写原子性,不等于线程安全
volatile 保证的是单次读或单次写的原子性,不是复合操作的原子性。例如:
这个操作包含“读取 → 修改 → 写入”三步,即使 counter 是 volatile long,依然可能发生竞态条件。要保证这类操作的线程安全,仍需用 AtomicLong、synchronized 或其他同步机制。
实际开发建议
- 若只需发布一个 64 位配置值(如开关标志、时间戳、版本号),且只写一次或极少更新,用
volatile long/double简洁高效; - 避免依赖
volatile实现计数器、累加器等需要读-改-写语义的逻辑; - 从 Java 5 开始,所有主流 JVM(包括 HotSpot)在 64 位平台下默认对
long/double读写就是原子的,但为跨平台兼容和语义清晰,仍推荐用volatile明确表达意图。

















