中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解JMM內存模型

發布時間:2021-09-29 16:14:27 來源:億速云 閱讀:128 作者:iii 欄目:大數據

本篇內容介紹了“如何理解JMM內存模型”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

1.計算機內存模型

CPU在執行的時候,肯定要有數據,而數據在內存中放著呢,這里的內存就是計算機的物理內存,剛開始還好,但是隨著技術的發展,CPU處理的速度越來越快,而從內存中讀取和寫入數據的過程和CPU的執行速度比起來差距就會越來越大,所說設計師,就在物理內存與CPU之間,加入了緩存的概念:也就是CPU在運行的時候,會將運算需要的數據從主存復制一份到CPU的高速緩存當中,那么CPU進行計算時就可以直接從它的高速緩存讀取數據和向其中寫入數據,當運算結束之后,再將高速緩存中的數據刷新到主存當中。

(說到這里,你應該能想到在高并發,使用多線程處理的時候,存在的問題。)

單核CPU只含有一套L1,L2,L3緩存;如果CPU含有多個核心,即多核CPU,則每個核心都含有一套L1(甚至和L2)緩存,而共享L3(或者和L2)緩存。

當你的計算式是:

單核CPU,單線程。 核心的緩存只被一個線程訪問。緩存獨占,不會出現訪問沖突等問題。

單核CPU,多線程。 進程中的多個線程會同時訪問進程中的共享數據,CPU將某塊內存加載到緩存后,不同線程在訪問相同的物理地址的時候,都會映射到相同的緩存位置,這樣即使發生線程的切換,緩存仍然不會失效。但由于任何時刻只能有一個線程在執行,因此不會出現緩存訪問沖突。

多核CPU,多線程。 每個核都至少有一個L1 緩存。多個線程訪問進程中的某個共享內存,且這多個線程分別在不同的核心上執行,則每個核心都會在各自的caehe中保留一份共享內存的緩沖。由于多核是可以并行的,可能會出現多個線程同時寫各自的緩存的情況,而各自的cache之間的數據就有可能不同。

2.JMM內存模型

JMM全稱為Java Memory Model  java內存模型,它只是一組規范,并不真實存在,(看好了,只是一組規范、一個定義),它描述的是一個規則。通過這組規范定義程序中的變量的訪問方式。以此來解決多核CPU多線程時造成的問題(請想一想為什么會是多核CPU多線程時)。

JMM規定了工作內存、主內存,而主內存是共享區域,所有線程都可以訪問,工作內存是每個線程的工作內存,每個線程對變量的操作必須在自己的工作內存中進行。在運行時將變量從主內存中拷貝到工作內存中,對變量進行操作,操作完后再將變量寫會主內存,不能直接在主內存中操作變量。再說一遍:這是規范,是java定義的一組程序運行時的規范。看到這,是不是發現與計算機的內存模型特別像

3.JAVA內存區域

在這里再說一下java的內存區域:堆、棧、方法區、本地方法區、程序計數器

  1. 方法區:線程共享區域,主要用于存儲虛擬機加載的類信息、常量、靜態變量等數據。

  2. 堆:線程共享區域,虛擬機啟動時創建,主要用于存放對象的實例,所以也是java垃圾回收最頻繁的一個區域

  3. 棧:線程私有區域,與線程同時創建,棧數量與線程數量相等,以棧幀定義,執行每個方法時,都會創建一個棧幀存儲方法的信息:操作數棧、動態鏈接方法、返回值、返回地址等信息,每個方法執行從調用到結束,對應著這個棧幀的入棧出棧。

  4. 程序計數器、本地方法棧我們先不關心,有心者請自行學習。

如果你看到這,我覺得你應該會疑惑,說JMM的時候,會什么要把計算機的內存模型、JAVA的內存區域都描述一下,稍后你就會知道。

在這里我還要再強調一遍,jmm內存模型的主內存和工作內存與java內存區域的堆、棧、方法區等不是同一個層次的,無法類比。一個是規范、規則,就相當于校規似的。如果真要對應,那就如同你想的  棧---工作內存,堆、方法區---主內存。

現在我要將這些聯系起來了:

首先jmm是一組規范,是java提出來的規范,那么java在設計的時候,肯定也符合這組規范。我認為java的內存區域就是根據jmm規范設計的,所以上面說了,他們不屬于一個層次,無法類比,只能說是java內存區域,符合jmm的規范。

然后我們也知道,線程是cpu調度的最小單元,也就是說cpu的內核執行線程,上面也說了,執行方法,也就是一個棧幀入棧出棧的過程,那么cpu內核執行線程,就是操作的棧中的數據,那么就是cpu內核把棧中的數據拷貝到它的緩存中去運行。可能有點模糊,我認為你就記住,cpu執行時的數據就是棧中的數據。

你可能在想,那堆中的數據時怎么操作的?我認為是這樣:看到這,我也認為電腦面前的你知道了堆在棧中存的是一個地址,那么cpu內核在運行時,不也是根據這個地址找到那個數據了嘛,對cpu來講,你就是一份數據,在它面前你跟棧中的數據都是一樣的,都是數據,然后加到它的緩存中。

如果你讀的有點蒙,那就請再讀幾遍,書讀百遍,其義自見:也就是說你在讀第一遍的時候,你根本就沒理解,你的腦子里只有讀過的字,并沒有理解到寫的含義,打個比方說:我說筷子,你腦海的潛意識中是筷子兩根棍的樣子,而不是“筷子”這兩個字。

然后,請回顧上面提到的兩個問題,我也在這貼出來一段代碼,以此來表示多核多線程產生的問題:

public class VolatileFaceThread{
    boolean isRunning = true;
    void m() {
        System.out.println("isRunning start");
        while(isRunning) {
        }
        System.out.println("isRunning end");
    }
    public static void main(String\[\] args) {
        VolatileFaceThread vft = new VolatileFaceThread();
        new Thread(vft :: m).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        vft.isRunning = false;
        System.out.println("update isRunning...");
    }
}

預期效果:新啟線程會一直循環下去

這段代碼,新啟的線程將會一直循環下去,不會被停止。試驗此段代碼時,如果有的實際效果是在主線程修改后,新啟的線程也跟著停止了,那么你的電腦可能1核在運行。(當初我在這被卡了好幾天,讓同事運行時,它運行的實際效果就是預期效果)。

這就是因為,兩個線程被兩個內核運行,他們把值讀取到自己的緩存中運行。而緩存是每個內核私有的,主線程修改了值,對新啟線程來說是不可見的,故新啟線程會一直循環。

那怎么解決呢,就是讓線程可見唄,java中有這一個關鍵字:volatile-----內存可見性、禁止指令重排序。

被volatile關鍵字修飾的變量對所有線程總是可見的,也就是在一個線程修改了一個被volatile關鍵字修飾變量的值,新值總是可以被其他線程立即得知。 

“如何理解JMM內存模型”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宁远县| 桂林市| 丰城市| 三台县| 新源县| 同德县| 彭山县| 余干县| 兴仁县| 东山县| 清河县| 濮阳县| 湖南省| 苏尼特左旗| 方山县| 墨竹工卡县| 余江县| 广河县| 全椒县| 大化| 睢宁县| 水城县| 云龙县| 庄河市| 洪湖市| 涟源市| 寻乌县| 南召县| 静安区| 平顺县| 镶黄旗| 绥芬河市| 西宁市| 雷山县| 安福县| 江山市| 合作市| 北流市| 杭锦后旗| 离岛区| 福安市|