java 多線程11:volatile關鍵字

來源:互聯網
上載者:User

標籤:資料拷貝   cep   ace   分享   import   方法   space   進程   執行個體變數   


直接先舉一個例子普通的線程執行個體變數的非可見度:

public class MyThread28 extends Thread{    private boolean isRunning = true;    public boolean isRunning()    {        return isRunning;    }    public void setRunning(boolean isRunning)    {        this.isRunning = isRunning;    }        public void run()    {        System.out.println("進入run了");        while (isRunning == true){}        System.out.println("線程被停止了");    }}
public static void main(String[] args){    try    {        MyThread28 mt = new MyThread28();        mt.start();        Thread.sleep(1000);        mt.setRunning(false);        System.out.println("已賦值為false");    }    catch (InterruptedException e)    {        e.printStackTrace();    }}

看一下運行結果:

進入run了已賦值為false

也許這個結果有點奇怪,明明isRunning已經設定為false了, 線程還沒停止呢?

這就要從Java記憶體模型(JMM)說起,這裡先簡單講,虛擬機器那塊會詳細講的。根據JMM,Java中有一塊主記憶體,不同的線程有自己的工作記憶體,同一個變數值在主記憶體中有一份,如果線程用到了這個變數的話,自己的工作記憶體中有一份一模一樣的拷貝。每次進入線程從主記憶體中拿到變數值,每次執行完線程將變數從工作記憶體同步回主記憶體中。

注意這裡的情況只會出現Server模式,Client模式不會出現,而且要先睡一段時間再設定false,估計是為了讓子線程read load 好主記憶體欄位吧,不設定睡覺的話,子線程來不及 read load 就會立刻停止了


出現列印結果現象的原因就是主記憶體和工作記憶體中資料的不同步造成的。因為執行run()方法的時候拿到一個主記憶體isRunning的拷貝,而設定isRunning是在main函數中做的,換句話說 ,設定的isRunning設定的是主記憶體中的isRunning,更新了主記憶體的isRunning,線程工作記憶體中的isRunning沒有更新,當然一直死迴圈了,因為對於線程來說,它的isRunning依然是true。

解決這個問題很簡單,給isRunning關鍵字加上volatile。加上了volatile的意思是,每次讀取isRunning的值的時候,都先從主記憶體中把isRunning同步到線程的工作記憶體中,再當前時刻最新的isRunning。看一下給isRunning加了volatile關鍵字的運行效果:

進入run了已賦值為false線程被停止了

看到這下線程停止了,因為從主記憶體中讀取了最新的isRunning值,線程工作記憶體中的isRunning變成了false,自然while迴圈就結束了。


volatile之前的普通線程記憶體模型


使用 volatile 之後






這裡可以參考 java虛擬機器9:Java的記憶體模型



volatile的作用就是這樣,被volatile修飾的變數,保證了每次讀取到的都是最新的那個值。安全執行緒圍繞的是可見度和原子性這兩個特性展開的,volatile解決的是變數在多個線程之間的可見度,但是無法保證原子性。

多提一句,synchronized除了保障了原子性外,其實也保障了可見度。因為synchronized無論是同步的方法還是同步的代碼塊,都會先把主記憶體的資料拷貝到工作記憶體中(synchronized  只要一經線程調用,無所謂你鎖的誰,只要跟進程相關的執行個體變數,靜態變數都會同步到主記憶體,實現可見度,下面可以看到例子),同步代碼塊結束,會把工作記憶體中的資料更新到主記憶體中,這樣主記憶體中的資料一定是最新的。



volatile非原子特性



運行結果


證明了非原子性,但是保證是可見度的
下面更改代碼 使用 synchronized 代替 volatile

運行結果







使用 synchronized 就沒必要使用 volatile 了



synchronized擁有volatile的同步功能






可以看的出來 ·synchronized  只要一經線程調用,無所謂你鎖的誰,只要跟進程相關的執行個體變數,靜態變數都會同步到主記憶體,實現可見度

java 多線程11:volatile關鍵字

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.