面試官:我問的是Java內存模型,你回答堆棧方法區幹嗎?

據說微信搜索《Java魚仔》會變動強哦!java

本文收錄於JavaStarter,裏面有我完整的Java系列文章,學習或面試均可以看看哦git

(一)概述

不少人會把Java內存區域(運行時數據區)和Java內存模型(JMM)搞混,這二者是徹底不同的東西。github

Java內存區域是指JVM運行時數據分區域存儲,而Java內存模型是定義了線程和主內存之間的抽象關係,瞭解Java內存模型是學好Java併發編程的基礎。面試

(二)Java內存模型

Java內存模型中規定了全部的變量都存儲在主內存中,每條線程還有本身的工做內存,線程對變量的全部操做都必須在工做內存中進行,而不能直接讀寫主內存中的變量。咱們來看一張圖:編程

在這裏插入圖片描述

每一個線程擁有一個本身的私有工做內存,須要變量時從主內存中拷貝一份到工做內存,若是更新過變量以後再將共享變量刷新到主內存。緩存

可是兩個線程之間,是沒有辦法讀取對方工做內存中的變量值的。看一個例子:微信

public class Test {
    private static boolean flag=false;
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("waiting");
                while (!flag){}
                System.out.println("in");
            }
        }).start();

        Thread.sleep(2000);
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("change flag");
                flag=true;
                System.out.println("change success");
            }
        }).start();
    }
}

首先定義了一個靜態變量flag爲false,A線程等待flag等於true後輸出in,因而咱們新開一個線程將flag修改成true。結果是A線程依舊沒法輸出in。併發

在這裏插入圖片描述

原理看Java內存模型的圖就理解了,不一樣的線程修改變量,對本地線程是不可見的。ide

(三)JMM數據的原子操做

經過上面這段代碼,咱們已經知道了Java內存模型的結構,那麼工做內存和主內存之間是如何讀取變量又是如何修改變量的呢?JMM提供了對變量的一系列原子操做。咱們先不講理論,看個圖,這個圖描述了上面一段代碼的執行過程:性能

在這裏插入圖片描述

整個過程一共十步,重複幾個步驟不講了,我把不重複的六個操做列一下:

read:從主內存讀取數據

load:將主內存讀取到的數據寫入工做內存

use :從工做內存中讀取數據來使用

assign:把計算好的值從新賦值到工做內存中

store:將工做內存數據寫入主內存

write:將store過去的變量賦值給主內存中的變量

經過上面的圖,對下面六個原子操做的理解應該能夠更加深入了。JMM的原子操做一共有八個,下面列出剩下的兩個

lock:將主內存變量加鎖,標識爲線程獨佔狀態

unlock:將主內存變量解鎖,解鎖後其餘線程能夠鎖定該變量

(四)JMM緩存不一致問題

從前面的例子咱們已經看到了,一個線程修改完數據,另一個線程沒法當即可見,這就是JMM緩存不一致的問題,有兩種解決辦法:

加鎖:

還記得咱們沒有用到過的JMM原操做的最後兩個嗎,lock和unlock,使用這兩個操做就能夠實現緩存一致性,一個線程想要獲取某個主內存變量時,先使用lock將主內存變量加鎖,只有他才能使用,等用完後再unlock,其餘線程才能競爭。可是加鎖意味着性能低。

MESI緩存一致性協議:

這個協議涉及到cpu的總線嗅探機制,從上面的JMM執行的流程圖中咱們能夠看到當某個線程修改了共享變量後,他會回寫到主內存,MESI緩存一致性協議就是經過cpu的總線嗅探機制,將其餘也正在使用該變量的線程的數據失效掉,使得這些線程要從新讀取主內存中的值,從而保證緩存最終一致性。(volatile的實現原理)

(五)總結

Java內存模型在多併發中十分重要,包括後面學習volatile或者synchronized這個關鍵字的時候,都會回到這個Java內存模型中。

相關文章
相關標籤/搜索