在java中,long和double都8个字节共64位(一个字节=8bit),那么如果是一个32位的系统,读写long或double的变量时,会不会涉及到原子性问题?答案是确定的,因为32位的系统要读完一个64位的变量,需要分两步执行,每次读取32位,这样就对double和long变量的赋值就会出现问题:
如果有两个线程同时写一个变量内存,一个进程写低32位,而另一个写高32位,这样将导致获取的64位数据是失效的数据。
public class LongTest implements Runnable{
private static long aLong = 0;
private volatile long value;
public LongTest(long value) {
this.setValue(value);
}
@Override
public void run() {
int i = 0;
while (i < 100000) {
LongTest.aLong = this.getValue();
i++;
long temp = LongTest.aLong;
if (temp != 1L && temp != -1L) {
System.out.println("出现错误结果" + temp);
System.exit(0);
}
}
System.out.println("运行正确");
}
public static void main(String[] args) throws InterruptedException {
// 获取并打印当前JVM是32位还是64位的
String sysNum = System.getProperty("sun.arch.data.model");
System.out.println("系统的位数:"+sysNum);
LongTest t1 = new LongTest(1);
LongTest t2 = new LongTest(-1);
Thread T1 = new Thread(t1);
Thread T2 = new Thread(t2);
T1.start();
T2.start();
T1.join();
T2.join();
}
public long getValue() {
return value;
}
public void setValue(long value) {
this.value = value;
}
}
上面的代码在32位环境和64位环境执行的结果是不一样的:
32位环境:出现错误结果
原因:32位环境无法一次读取long类型数据,多线程环境下对aLong变量的读写是不完整的,导致temp变量既不等于1也不等于01
64位环境:运行正确
解决方法:因此需要使用volatile关键字来防止此类现象
- 对于64位的long和double,如果没有被volatile修饰,那么对其操作可以不是原子的。在操作的时候,可以分成两步,每次对32位操作。
- 如果使用volatile修饰long和double,那么其读写都是原子操作
如果是在64位的系统中,那么对64位的long和double的读写都是原子操作的。即可以以一次性读写long或double的整个64bit。
参考:https://mp.weixin.qq.com/s/Zfv9SjQeAtjnT4xVwTsa2g
https://my.oschina.net/u/2401092/blog/1920239