java學習:JMM(java memory model)、volatile、synchronized、AtomicXXX理解

來源:互聯網
上載者:User

標籤:記憶體模型   system   自己的   main   理解   工作   atomic   mode   排序   

一、JMM(java memory model)記憶體模型

從網上淘來二張圖:

上面這張圖說的是,在多核CPU的系統中,每個核CPU內建快取,然後電腦主板上也有一塊記憶體-稱為主內(即:記憶體條)。工作時,CPU的快取中的資料通過一系列手段來保證與主內的資料一致(CacheCoherence),更直白點,快取要從主內中load資料,處理完以後,還要save回主存。

 

說的是,java中的各種變數(variable)儲存在主存中,然後每個線程自己也有自己的工作記憶體區(working memory),工作時,線程從主存中把變數副本load到自己的工作記憶體區,處理完了,再save回主存。

好象很明白,沒有什麼不好理解的:),

問題來了,如果有二個線程:線程A與線程B, A從主存中讀取了變數x(到自己的的工作記憶體區),正準備處理,這時B修改了主存中的變數x,線程A能看見這種變化嗎?(是否需要及時從主存中,載入最新的值),這個問題稱為共用變數的可見度。

 

二、volatile、synchronized、AtomicXXX

直接上碼:

2.1 版本1

package test.cn.mwee.order.monitor;/** * Created by 菩提樹下的楊過 on 2017/6/11. */public class ThreadTest extends Thread {    private static boolean flag = false;    public void run() {        System.out.println("t1:" + Thread.currentThread().getId());        while (!flag) {        }        System.out.println("quit!");    }    public static void main(String[] args) throws InterruptedException {        ThreadTest t1 = new ThreadTest();        t1.start();        Thread.sleep(50);        ThreadTest.flag = true;        System.out.println("main:" + Thread.currentThread().getId());    }}

ThreadTest是一個線程類,裡面有一個靜態變數flag,然後寫了個main方法做測試。

註:在t1啟動完成後,主線程中修改了ThreadTest的靜態變數值flag,這時t1的run方法裡的while迴圈,其實是看不見主線程對這個值的修改,所以程式始終不能退出,列印不出那一行quit.

 

2.2 版本2

package test.cn.mwee.order.monitor;/** * Created by 菩提樹下的楊過 on 2017/6/11. */public class ThreadTest extends Thread {    private static boolean flag = false;    public void run() {        System.out.println("t1:" + Thread.currentThread().getId());        while (!flag) {            synchronized (Class.class) {            }        }        System.out.println("quit!");    }    public static void main(String[] args) throws InterruptedException {        ThreadTest t1 = new ThreadTest();        t1.start();        Thread.sleep(50);        ThreadTest.flag = true;        System.out.println("main:" + Thread.currentThread().getId());    }}  

相對版本1,while迴圈中增加了一個synchronized同步代碼塊,雖然裡面啥代碼也沒有,但是再次運行,能正常quit了(想下為啥?)

答案:(也是從網上抄來的)

synchronized關鍵字強制實現一個互斥鎖,使得被保護的代碼塊在同一時間只能有一個線程進入並執行。同時也帶另外一個作用:線上程進入synchronized塊之前,會把工作存記憶體中的所有內容映射到主記憶體上,然後把工作記憶體清空再從主儲存空間上拷貝最新的值。而線上程退出synchronized塊時,同樣會把工作記憶體中的值對應到主記憶體,但此時並不會清空工作記憶體。這樣,工作記憶體中的值和主記憶體中的值是一致的,保證了資料的一致性!(換句話說,run中的while看到了主存中的flag變數值的改變)

思考題:如果在while{}裡寫一行println列印輸出,即:

        while (!flag) {            System.out.println("flag=" + flag);        }  

也能正常退出,留給大家去想。

 

2.3 版本3

package test.cn.mwee.order.monitor;/** * Created by 菩提樹下的楊過 on 2017/6/11. */public class ThreadTest extends Thread {    private volatile static boolean flag = false;    public void run() {        System.out.println("t1:" + Thread.currentThread().getId());        while (!flag) {        }        System.out.println("quit!");    }    public static void main(String[] args) throws InterruptedException {        ThreadTest t1 = new ThreadTest();        t1.start();        Thread.sleep(50);        ThreadTest.flag = true;        System.out.println("main:" + Thread.currentThread().getId());    }}  

相對版本1,flag變數前加了關鍵字volatile,它能保證對該變數的修改,同步到其它線程,即其它線程讀取flag時,看到的就是變化後的最新值,同時volatile還能防止指令重排序。運行下,也能如期列印出quit,程式退出。

註:volatile只能保證其它線程看到的變數值是最新的,但是並不保證原子性(換句話說,高並發情況下,仍然無法100%保證安全執行緒)

 

2.4 版本4

package test.cn.mwee.order.monitor;import java.util.concurrent.atomic.AtomicBoolean;/** * Created by 菩提樹下的楊過 on 2017/6/11. */public class ThreadTest extends Thread {    private static AtomicBoolean flag = new AtomicBoolean(false);    public void run() {        System.out.println("t1:" + Thread.currentThread().getId());        while (!flag.get()) {        }        System.out.println("quit!");    }    public static void main(String[] args) throws InterruptedException {        ThreadTest t1 = new ThreadTest();        t1.start();        Thread.sleep(50);        ThreadTest.flag.set(true);        System.out.println("main:" + Thread.currentThread().getId());    }}  

與上一個版本相比,使用了可以保證原子性,又不用加同步鎖的並發包裡的AtomicXXX系列類,同樣也可以正常列印出quit,推薦使用這個。

如果感興趣的話,可以看下AtomicBoolean的源碼,其實是藉助volatile以及CAS來實現的,源碼一看便知,不再囉嗦。

java學習:JMM(java memory model)、volatile、synchronized、AtomicXXX理解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.