long 和 double 的原子性问题

       在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

你可能感兴趣的:(long 和 double 的原子性问题)