1. 程式人生 > >JAVA併發程式設計:volatile關鍵字深入解析

JAVA併發程式設計:volatile關鍵字深入解析

生活

天氣賊好的一個禮拜二。
生活就是生下來活下去。

簡述

volatile是JAVA中的一個關鍵字,在JDK1.5以前據說飽受爭議,在程式中使用經常出現一些出入意料的結果。

這個麼,從volatile的翻譯就能看出來,就是不穩定的意思嘛。

JDK1.5以後,volatile才重獲生機。(我認為是Doug Lea寫的併發包把它發揚光大了)。

學習它有什麼用?

1、有助於記憶體模型的深入瞭解
2、有助於併發程式設計的深入學習
3、方便後期與synchronized關鍵字對比學習

特性

1、可見性
2、有序性(一定程式上保障有序性)

注意 沒有原子性,所以單純使用這個關鍵字,並不是執行緒安全的。需要搭配其他鎖來保證執行緒安全。

使用

直接套用前面的場景

場景說明:
兩個執行緒共享一個變數stop.
A執行緒,當stop為false,則一直執行;為true則停止。
B執行緒,設定stop為true

public class Test {
    static  boolean stop;

    public static void main(String[] args) throws InterruptedException {

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("執行緒A執行中");
                while (!stop);
                System.out.println("執行緒A已停止");
            }
        }).start();

        Thread.sleep(10);


        new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("執行緒B執行中");
               stop = true;
               System.out.println("stop設定為true,執行緒B已停止");
           }
       }).start();
    }
}

其中一次執行結果:
執行緒A執行中
執行緒B執行中
stop設定為true,執行緒B已停止

由此見得,一個普通的變數在多執行緒環境下不具有可見性。

只需要給stop變數加上關鍵字volatile,在多執行緒環境下就不會在出現不可見的情況。

PS:上面講到volatile實現可見性,其實我認為這個可見性本身就是基於 一定程度的有序性實現的。即對volatile的變數讀取之前,必須保證前面的更新已經刷入主記憶體。
這是通過記憶體屏障來禁止重排序實現了一定的有序性,從而達到可見性。

實現原理

關於volatile的實現原理,我看了很多部落格,講的很多,都是對的,但是講的實在太多了,本來想把他們講的東西抄下來,感覺意義不大。自己簡單的分析一下:
1、為什麼會出現不可見性的問題?
原因在於:多執行緒環境下存在工作記憶體和主記憶體,每個執行緒的工作記憶體都是獨立的,在使用一個變數之前要先拷貝一份副本到自己的工作記憶體,更新一個變數,需要先在自己的工作記憶體中更新,在刷入到主記憶體。
不可見性出現的問題就在於A執行緒讀取變數的時候,可能B執行緒更新了但是並沒有刷入主記憶體。導致不一致的情況。

2、如果避免不可見性?
從現實角度分析,就必須強制要求在A執行緒讀取變數之前其他執行緒的更新操作必須刷入主記憶體。也就是volatile的關鍵字語義,被volatile修飾的變數,被一個執行緒修改後可以及時被其他執行緒讀取到。

3、如果實現2中提到的避免不可見性的操作。
兩種辦法:
3.1互斥鎖:即多個執行緒訪問使用同一個變數時,同一個時刻只由一個執行緒上鎖操作訪問這個變數,訪問結束unlock()後其他執行緒才可以訪問,強制實現了可見和有序。
3.2volatile:他的實現原理就是jvm記憶體模型中本身的記憶體屏障,在volatile寫的後面加上store load 屏障,禁止volatile寫與後面的操作重排序,即volatile寫必須先於後面的操作。

總結反思

這是我理解的volatile,有不對和不恰當的煩請指正!