Volatile關鍵字淺析

一、保持多線程環境中共享變量的可見性。

       在多線程環境下,每個線程都有一個自己的線程棧,對於共享的變量(比如堆中new的變量),每個線程棧都會拷貝一個該變量的副本,使用volatile修飾的變量,當線程修改當前棧程棧的副本時,修改後的副本數據會馬上更新到共享變量上。

       如下圖所示,我們把變量data用volatile修飾,然後啓動兩個線程分別對data進行自增操作,在初始化的步驟中,線程1和線程2分別拷貝一份變量的副本到兩個線程的棧中,兩個線程內部分別進行循環,每循環一次data就自增一次。而因爲data被volatile關鍵字修飾,則每自增一次,線程棧中的data變量副本都會強制更新到共享變量data中。同時,其它線程中的data副本將被置爲無效,其它線程在使用data時會從新從堆中讀取。

 

       下面的代碼,就是圖中線程執行函數的例子:

public class MyRunnable implements Runnable {
    public static Integer data = 0;
    private Integer spon = 0;
    @Override
    public void run() {
        try {
            while (true) {
                data++;
                Thread.sleep(1000 * (spon / 2 + 1));
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

需要注意的是:

(1)volatile關鍵字可以強制程序將線程棧中的副本刷新的共享變量,但不是說:如果一個共享變量沒有被voltile修飾,它的副本在線程中被修改時就不會馬上更新到共享變量中。實際上這種情況很少會發生。

(2)因爲int等基本類型在深拷貝時才具有原子性,volatile關鍵字一般只用來修飾基本的數據類型。

(3)volatile關鍵字並不能代替synchronized等鎖進行線程間的同步作用,比如在上述的代碼中,data的自增操作不具有原子性,它實際分爲兩個過程,一是告訴緩存的數據進行自增操作,二是自增後的數據更新到內存。

 

二、禁止編譯器的指令重排功能

      在默認情況下,java編譯器具有指令重拍功能,比如以下代碼:

int a=1;
int b=2;
int c=a+b;

       編譯器在進行編譯時,可能a=1在前面,也可能b=2在前面。但是並不是所有的代碼都會被編譯器指令重拍,比如下面的代碼:

int a=1;
a=a+1;
system.out.print(a);

       這種情況下,第2行的代碼直接影響到了第3行的打印結果,編譯器肯定不會進行指令重排。

       在多線程的條件下,指令重拍可能會影響到執行執行的結果,比如下面的代碼:

共享變量:

boolean flag=false;
int data=1;

線程1:

if(flag=-true){
    system.out.println(data);
}

線程2:

data++;
flag=true;

        顯然線程2的兩條指令如果重排將會直接影響線程1的輸出結果,此時我們可以用volatile關鍵字修飾上述兩個變量,這樣禁止了編譯器的指令重排。volatile在禁止指令重拍方面應用最廣的應該算是在單例模式上,如下代碼:

 public class MyObj {
    private static volatile MyObj instance = new MyObj();
    public static MyObj getInstance() {
        return instance;
    }
}

        在執行MyObj instance = new MyObj();時實際上被分成了三個步驟:

  • 1、在棧中創建一片內存給instance變量。
  • 2、在堆中new一個MyObj對象。
  • 3、將步驟2中的對象指向步驟1中的變量。

        在多線程環境下,如果編譯器進行了指令重排,將步驟2和步驟3對調,那麼我們在使用MyObj的單例對象時很可能會出現null指針異常。所以最安全的方法就是將instance對象用volatile關鍵字進行修飾,禁止編譯器指令重排。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章