volatile關鍵字的用法

關鍵字volatile的主要作用是使變量在多個線程間可見,強制從公共堆棧中取得變量的值,而不是從線程的私有數據棧中取得變量的值。這麼說很難理解,我們直接看代碼例子來說明。

創建一個RunThread.java的類如下:

public class RunThread extends Thread{
    private boolean isRunning = true;

    public boolean isRunning() {
        return isRunning;
    }

    public void setRunning(boolean running) {
        isRunning = running;
    }

    @Override
    public void run() {
        System.out.println("進入run了");
        while(isRunning){

        }
        System.out.println("線程被停止了");
    }
}

運行類Run代碼如下:

public class RunTest {
    public static void main(String[] args){
        try {
            RunThread thread = new RunThread();
            thread.start();
            Thread.sleep(1000);
            thread.setRunning(false);
            System.out.println("已經賦值false");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

運行RunTest結果如下:

進入run了
已經賦值false

從結果看來,線程內部一執行了死循環,代碼System.out.println(“線程被停止了”)並沒有被執行。這是爲什麼呢,明明已經通過 thread.setRunning(false)改變了isRunning的值啊。

這是因爲在啓動RunThread.java線程時,變量private boolean isRunning = true;存在於公共堆棧及線程的私有堆棧中,線程一直在私有堆棧中取得isRunning的值是true。而代碼thread.setRunning(false)雖然被執行,更新的確是公共堆棧中的isRunning變量值false,所以一直還是處於死循環狀態。這個問題其實就是私有堆棧中的值和公共堆棧中的值不同步造成。解決這個問題就要用到volatile關鍵字,當線程訪問isRunning這個變量時,強制從公共堆棧中進行取值。

將RunThread.java類代碼變更如下:

public class RunThread extends Thread{

    volatile private volatile boolean isRunning = true;
    public boolean isRunning() {
        return isRunning;
    }
    public void setRunning(boolean running) {
        isRunning = running;
    }

    @Override
    public void run() {
        System.out.println("進入run了");
        while(isRunning){

        }
        System.out.println("線程被停止了");
    }
}

再運行後,可看到運行結果:線程被終止了。
這裏寫圖片描述


總結:使用volatile關鍵字,強制從公共內存中讀取變量,增加了實例變量在多個線程之間的可見性。

這裏將關鍵字synchronized 和 volatile進行一下比較:

1.volatile是線程同步的輕量級實現,所以volatile性能synchronized要好,並且volatile只能修飾於變量,而synchronized可以修飾方法,以及代碼塊。

2.多線程訪問volatile不會發生阻塞,而synchronized會出現阻塞;

3.volatile能保證數據的可見性,但不能保證原子性,這也是volatile最致命的缺點;而synchronized可以保證原子性,也可以間接保證可見性,因爲他會將私有內存和公共內存中的數據同步。

4.關鍵字volatile解決的是變量在多個線程之間的可見性;而synchronized關鍵字解決的是多個線程之間訪問資源的同步性。

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