java中long和double類型操做的非原子性探究

Java中的原子操做包括:java

1)除long和double以外的基本類型的賦值操做eclipse

2)全部引用reference的賦值操做ide

3)java.concurrent.Atomic.* 包中全部類的一切操做。this

 

可是java對long和double的賦值操做是非原子操做!!long和double佔用的字節數都是8,也就是64bits。在32位操做系統上對64位的數據的讀寫要分兩步完成,每一步取32位數據。這樣對double和long的賦值操做就會有問題:若是有兩個線程同時寫一個變量內存,一個進程寫低32位,而另外一個寫高32位,這樣將致使獲取的64位數據是失效的數據。所以須要使用volatile關鍵字來防止此類現象。volatile自己不保證獲取和設置操做的原子性,僅僅保持修改的可見性。可是java的內存模型保證聲明爲volatile的long和double變量的get和set操做是原子的。(from http://www.iteye.com/topic/213794)atom

 

舉個例子來講:(example is from http://stackoverflow.com/questions/17481153/long-and-double-assignments-are-not-atomic-how-does-it-matter)spa

public class UnatomicLong implements Runnable {操作系統

    private static long test = 0;.net

 

    private final long val;線程

 

    public UnatomicLong(long val) {進程

        this.val = val;

    }

 

    @Override

    public void run() {

        while (!Thread.interrupted()) {

            test = val; //兩個線程都試圖將本身的私有變量val賦值給類私有靜態變量test

        }

    }

 

    public static void main(String[] args) {

        Thread t1 = new Thread(new UnatomicLong(-1));

        Thread t2 = new Thread(new UnatomicLong(0));

 

        System.out.println(Long.toBinaryString(-1));

        System.out.println(pad(Long.toBinaryString(0), 64));

 

        t1.start();

        t2.start();

 

        long val;

        while ((val = test) == -1 || val == 0) { 

       //若是靜態成員test的值是-1或0,說明兩個線程操做沒有交叉

        }

 

        System.out.println(pad(Long.toBinaryString(val), 64));

        System.out.println(val);

 

        t1.interrupt();

        t2.interrupt();

    }

 

    // prepend 0s to the string to make it the target length

    private static String pad(String s, int targetLength) {

        int n = targetLength - s.length();

        for (int x = 0; x < n; x++) {

            s = "0" + s;

        }

        return s;

    }

}

 

運行發現程序在while循環時進入了死循環,這是由於使用的JVM是64bits。在64位JVM中double和long的賦值操做是原子操做。

在eclipse中修改jre爲一個32bit的JVM地址,則會有以下運行結果:

1111111111111111111111111111111111111111111111111111111111111111

0000000000000000000000000000000000000000000000000000000000000000

0000000000000000000000000000000011111111111111111111111111111111 

//很明顯test的值被破壞了

4294967295

相關文章
相關標籤/搜索