volatile 对 int 和 long 修改的区别
volatile 对 int 和 long 修改的区别
volatile
关键字在 Java 中用于保证变量的可见性和有序性,但对于不同基本数据类型(特别是 int
和 long
),其行为有一些重要区别。
主要区别
1. 原子性差异
-
对于 int (32位):
volatile int
的读写操作是原子性的- 在32位和64位JVM上都是原子操作
-
对于 long (64位):
- 在32位JVM上,
volatile long
的读写不是原子性的(可能被拆分为两个32位操作) - 在64位JVM上,
volatile long
的读写是原子性的 - Java 5+ 的 JMM (Java内存模型) 保证在64位JVM上
volatile long
的原子性
- 在32位JVM上,
2. 性能考虑
volatile long
在32位架构上可能有更高的开销,因为需要保证64位操作的原子性volatile int
在所有平台上性能差异不大
底层原理
32位JVM上的 long 处理
在32位架构上,64位的 long 操作可能需要两条指令完成:
volatile long value = 0L;// 写操作可能被拆分为两个32位写
value = 0x123456789ABCDEF0L;
// 实际可能执行:
// 写入低32位 (0x9ABCDEF0)
// 写入高32位 (0x12345678)
volatile
保证这些操作的有序性和可见性,但在32位JVM上不保证这两部分操作的原子性。
实际影响
线程安全场景
// 安全 - volatile int 总是原子操作
volatile int intValue;// 在64位JVM安全,32位JVM不安全
volatile long longValue;
解决方案
如果需要保证 long 在32位JVM上的原子性:
-
使用 AtomicLong:
AtomicLong atomicLong = new AtomicLong();
-
加锁同步:
private final Object lock = new Object(); private long value;public void setValue(long v) {synchronized(lock) {this.value = v;} }
JVM实现差异
JVM类型 | int (32位) | long (64位) |
---|---|---|
32位JVM | 原子操作 | 非原子操作 |
64位JVM | 原子操作 | 原子操作 |
最佳实践
- 对于计数器等简单场景,优先使用
volatile int
- 在32位JVM环境需要原子性long操作时,使用
AtomicLong
- 在64位JVM上,
volatile long
可以安全使用 - 考虑使用
@Contended
注解防止伪共享(Java 8+)
总结:volatile
对 int
的修改在所有平台上都是原子性的,而对 long
的修改在32位JVM上不具有原子性,这是两者最关键的差异。