欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

如何理解JMM內(nèi)存模型

本篇內(nèi)容介紹了“如何理解JMM內(nèi)存模型”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

成都創(chuàng)新互聯(lián)主營城關(guān)網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶APP軟件開發(fā),城關(guān)h5小程序開發(fā)搭建,城關(guān)網(wǎng)站營銷推廣歡迎城關(guān)等地區(qū)企業(yè)咨詢

1.計(jì)算機(jī)內(nèi)存模型

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

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

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

當(dāng)你的計(jì)算式是:

單核CPU,單線程。核心的緩存只被一個(gè)線程訪問。緩存獨(dú)占,不會(huì)出現(xiàn)訪問沖突等問題。

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

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

2.JMM內(nèi)存模型

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

JMM規(guī)定了工作內(nèi)存、主內(nèi)存,而主內(nèi)存是共享區(qū)域,所有線程都可以訪問,工作內(nèi)存是每個(gè)線程的工作內(nèi)存,每個(gè)線程對變量的操作必須在自己的工作內(nèi)存中進(jìn)行。在運(yùn)行時(shí)將變量從主內(nèi)存中拷貝到工作內(nèi)存中,對變量進(jìn)行操作,操作完后再將變量寫會(huì)主內(nèi)存,不能直接在主內(nèi)存中操作變量。再說一遍:這是規(guī)范,是java定義的一組程序運(yùn)行時(shí)的規(guī)范。看到這,是不是發(fā)現(xiàn)與計(jì)算機(jī)的內(nèi)存模型特別像

3.JAVA內(nèi)存區(qū)域

在這里再說一下java的內(nèi)存區(qū)域:堆、棧、方法區(qū)、本地方法區(qū)、程序計(jì)數(shù)器

  1. 方法區(qū):線程共享區(qū)域,主要用于存儲虛擬機(jī)加載的類信息、常量、靜態(tài)變量等數(shù)據(jù)。

  2. 堆:線程共享區(qū)域,虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建,主要用于存放對象的實(shí)例,所以也是java垃圾回收最頻繁的一個(gè)區(qū)域

  3. 棧:線程私有區(qū)域,與線程同時(shí)創(chuàng)建,棧數(shù)量與線程數(shù)量相等,以棧幀定義,執(zhí)行每個(gè)方法時(shí),都會(huì)創(chuàng)建一個(gè)棧幀存儲方法的信息:操作數(shù)棧、動(dòng)態(tài)鏈接方法、返回值、返回地址等信息,每個(gè)方法執(zhí)行從調(diào)用到結(jié)束,對應(yīng)著這個(gè)棧幀的入棧出棧。

  4. 程序計(jì)數(shù)器、本地方法棧我們先不關(guān)心,有心者請自行學(xué)習(xí)。

如果你看到這,我覺得你應(yīng)該會(huì)疑惑,說JMM的時(shí)候,會(huì)什么要把計(jì)算機(jī)的內(nèi)存模型、JAVA的內(nèi)存區(qū)域都描述一下,稍后你就會(huì)知道。

在這里我還要再強(qiáng)調(diào)一遍,jmm內(nèi)存模型的主內(nèi)存和工作內(nèi)存與java內(nèi)存區(qū)域的堆、棧、方法區(qū)等不是同一個(gè)層次的,無法類比。一個(gè)是規(guī)范、規(guī)則,就相當(dāng)于校規(guī)似的。如果真要對應(yīng),那就如同你想的  棧---工作內(nèi)存,堆、方法區(qū)---主內(nèi)存。

現(xiàn)在我要將這些聯(lián)系起來了:

首先jmm是一組規(guī)范,是java提出來的規(guī)范,那么java在設(shè)計(jì)的時(shí)候,肯定也符合這組規(guī)范。我認(rèn)為java的內(nèi)存區(qū)域就是根據(jù)jmm規(guī)范設(shè)計(jì)的,所以上面說了,他們不屬于一個(gè)層次,無法類比,只能說是java內(nèi)存區(qū)域,符合jmm的規(guī)范。

然后我們也知道,線程是cpu調(diào)度的最小單元,也就是說cpu的內(nèi)核執(zhí)行線程,上面也說了,執(zhí)行方法,也就是一個(gè)棧幀入棧出棧的過程,那么cpu內(nèi)核執(zhí)行線程,就是操作的棧中的數(shù)據(jù),那么就是cpu內(nèi)核把棧中的數(shù)據(jù)拷貝到它的緩存中去運(yùn)行。可能有點(diǎn)模糊,我認(rèn)為你就記住,cpu執(zhí)行時(shí)的數(shù)據(jù)就是棧中的數(shù)據(jù)。

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

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

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

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...");
    }
}

預(yù)期效果:新啟線程會(huì)一直循環(huán)下去

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

這就是因?yàn)椋瑑蓚€(gè)線程被兩個(gè)內(nèi)核運(yùn)行,他們把值讀取到自己的緩存中運(yùn)行。而緩存是每個(gè)內(nèi)核私有的,主線程修改了值,對新啟線程來說是不可見的,故新啟線程會(huì)一直循環(huán)。

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

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

“如何理解JMM內(nèi)存模型”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

網(wǎng)頁標(biāo)題:如何理解JMM內(nèi)存模型
本文網(wǎng)址:http://www.chinadenli.net/article34/peiese.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗(yàn)企業(yè)建站網(wǎng)站排名全網(wǎng)營銷推廣小程序開發(fā)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

綿陽服務(wù)器托管