最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java內(nèi)存模型的深入講解

 更新時(shí)間:2021年07月06日 09:03:28   作者:surzia  
這篇文章主要給大家介紹了關(guān)于Java內(nèi)存模型的相關(guān)資料,我們常說(shuō)的JVM內(nèi)存模式指的是JVM的內(nèi)存分區(qū),而Java內(nèi)存模式是一種虛擬機(jī)規(guī)范,需要的朋友可以參考下

Java內(nèi)存模型展示了Java虛擬機(jī)是如何與計(jì)算機(jī)內(nèi)存交互的,解決多線程讀寫(xiě)共享內(nèi)存時(shí)資源訪問(wèn)的問(wèn)題。

內(nèi)存模型

Java虛擬機(jī)中的內(nèi)存模型將線程棧與堆劃分開(kāi),下圖描述了Java內(nèi)存模型的邏輯圖。

每個(gè)線程都要自己的線程棧,棧中存儲(chǔ)著線程執(zhí)行到當(dāng)前位置所調(diào)用的方法信息,線程執(zhí)行代碼時(shí),線程棧會(huì)不斷執(zhí)行入棧和出棧操作。

線程棧中會(huì)存儲(chǔ)所有被調(diào)用的方法中定義的變量,并且自己訪問(wèn)自己棧中的變量,別的線程不可見(jiàn)。即使兩個(gè)線程執(zhí)行相同的代碼,也會(huì)在線程自己的棧中重復(fù)創(chuàng)建變量。一個(gè)線程可能會(huì)傳遞變量副本給另一個(gè)線程,但不能共享變量本身。

在棧中變量存儲(chǔ)形式也有所不同。屬于基本變量類(lèi)型(int,byte,long,boolean,char,double,float,short)的變量,會(huì)直接將變量值存儲(chǔ)在棧中,而其余類(lèi)型的變量的值被存儲(chǔ)在堆中,線程棧中只保留指向堆中變量地址的指針。
堆中則存儲(chǔ)Java程序中創(chuàng)建的所有對(duì)象,不管是什么線程創(chuàng)建的。創(chuàng)建對(duì)象并將其分配給局部變量,或者將其創(chuàng)建為另一個(gè)對(duì)象的成員變量都沒(méi)有影響,該對(duì)象仍存儲(chǔ)在堆中。

值得注意的是,Java中的靜態(tài)類(lèi)變量也會(huì)隨著類(lèi)初始化而存儲(chǔ)在堆中。

有指向?qū)ο笾羔樀乃芯€程都可以訪問(wèn)堆上的對(duì)象。當(dāng)線程可以訪問(wèn)對(duì)象時(shí),它也可以訪問(wèn)該對(duì)象的成員變量。如果兩個(gè)線程同時(shí)在同一個(gè)對(duì)象上調(diào)用一個(gè)方法,則它們都將有權(quán)訪問(wèn)該對(duì)象的成員變量,但是每個(gè)線程將擁有自己的局部變量副本。

兩個(gè)線程有一組局部變量,指向堆上的共享對(duì)象。這兩個(gè)線程分別具有對(duì)同一對(duì)象的不同指針。它們的指針也是局部變量,因此存儲(chǔ)在每個(gè)線程的線程棧中(在每個(gè)線程上)。但是,兩個(gè)不同的指針指向堆上的同一對(duì)象。
下面的代碼塊就是上圖的一個(gè)實(shí)際例子。

public class MyRunnable implements Runnable() {

    public void run() {
        methodOne();
    }

    public void methodOne() {
        int localVariable1 = 45;
        MySharedObject localVariable2 = MySharedObject.sharedInstance;
        //...
        methodTwo();
    }

    public void methodTwo() {
        Integer localVariable1 = new Integer(99);
        //...
    }
}
public class MySharedObject {

    //static variable pointing to instance of MySharedObject
    public static final MySharedObject sharedInstance = new MySharedObject();

    //member variables pointing to two objects on the heap
    public Integer object2 = new Integer(22);
    public Integer object4 = new Integer(44);

    public long member1 = 12345;
    public long member2 = 67890;
}

硬件架構(gòu)

現(xiàn)代硬件的內(nèi)存架構(gòu)與Java內(nèi)存模型還是有些不同的,了解硬件架構(gòu)對(duì)理解Java內(nèi)存模型也有幫助。簡(jiǎn)單的硬件架構(gòu)圖如下:

現(xiàn)代計(jì)算機(jī)一般是多核CPU,一般不止一個(gè)CPU,因此多個(gè)線程是可能在物理意義上并發(fā)運(yùn)行的。這意味著,如果Java應(yīng)用程序是多線程的,則每個(gè)CPU可能在Java應(yīng)用程序中同時(shí)(并發(fā))運(yùn)行一個(gè)線程。

每個(gè)CPU包含一組寄存器,這些寄存器本質(zhì)上是CPU內(nèi)存儲(chǔ)器。CPU在這些寄存器上執(zhí)行操作的速度比對(duì)主存儲(chǔ)器中的變量執(zhí)行操作的速度快得多,這是因?yàn)镃PU可以比訪問(wèn)主存儲(chǔ)器更快地訪問(wèn)這些寄存器。

每個(gè)CPU可能還具有一個(gè)CPU高速緩存。實(shí)際上,大多數(shù)現(xiàn)代CPU都有一定大小的高速緩存。CPU可以比其主存儲(chǔ)器更快地訪問(wèn)其高速緩存,但是通常不如其訪問(wèn)其內(nèi)部寄存器的速度快。因此,CPU高速緩存存儲(chǔ)器位于內(nèi)部寄存器和主存儲(chǔ)器之間的速度之間。某些CPU可能具有多個(gè)高速緩存層(L1和L2 Cache)。了解Java內(nèi)存模型如何與內(nèi)存交互并不是很重要,重要的是要知道CPU可以具有某種高速緩存層。

計(jì)算機(jī)還包含一個(gè)主存儲(chǔ)區(qū)(RAM)。所有CPU都可以訪問(wèn)主存儲(chǔ)器。主存儲(chǔ)區(qū)通常比CPU的高速緩存大得多。

通常,當(dāng)CPU需要訪問(wèn)主內(nèi)存時(shí),它將部分主內(nèi)存讀入其CPU緩存中。它甚至可以將緩存的一部分讀入其內(nèi)部寄存器,然后對(duì)其執(zhí)行操作。當(dāng)CPU需要將結(jié)果寫(xiě)回主存儲(chǔ)器時(shí),它將把值從其內(nèi)部寄存器刷新到高速緩存,然后在某個(gè)時(shí)候?qū)⒅邓⑿禄刂鞔鎯?chǔ)器。

當(dāng)CPU需要將其他內(nèi)容存儲(chǔ)在高速緩存中時(shí),通常會(huì)將高速緩存中存儲(chǔ)的值刷新回主存儲(chǔ)器。CPU高速緩存可以一次將數(shù)據(jù)寫(xiě)入其部分內(nèi)存,并一次刷新其部分內(nèi)存。它不必每次更新都讀取/寫(xiě)入完整的緩存。通常,緩存在稱為“緩存行”的較小存儲(chǔ)塊中更新,可以將一個(gè)或多個(gè)高速緩存行讀入高速緩存存儲(chǔ)器,并且可以將一個(gè)或多個(gè)高速緩存行再次刷新回主存儲(chǔ)器。

Java內(nèi)存模型與硬件關(guān)聯(lián)

如前所述,Java內(nèi)存模型和硬件內(nèi)存體系結(jié)構(gòu)是不同的,硬件內(nèi)存體系結(jié)構(gòu)不能區(qū)分線程堆棧和堆。在硬件上,線程堆棧和堆都位于主內(nèi)存中。線程堆棧和堆的某些部分有時(shí)可能會(huì)出現(xiàn)在CPU緩存和內(nèi)部CPU寄存器中。下圖對(duì)此進(jìn)行了說(shuō)明:

當(dāng)對(duì)象和變量可以存儲(chǔ)在計(jì)算機(jī)的各種不同存儲(chǔ)區(qū)域中時(shí),可能會(huì)出現(xiàn)某些問(wèn)題。 兩個(gè)主要問(wèn)題是:

  • 線程更新(寫(xiě)入)到共享變量的可見(jiàn)性。
  • 讀取,檢查和寫(xiě)入共享變量時(shí)的競(jìng)爭(zhēng)條件。

對(duì)象的可見(jiàn)性

如果兩個(gè)或多個(gè)線程共享一個(gè)對(duì)象,而沒(méi)有正確使用volatile關(guān)鍵字,則一個(gè)線程對(duì)共享對(duì)象進(jìn)行的更新可能對(duì)其他線程不可見(jiàn)。

每個(gè)線程都可以擁有自己的共享庫(kù)副本,每個(gè)副本位于不同的CPU緩存中。想象一下,共享對(duì)象最初存儲(chǔ)在主存儲(chǔ)器中。然后,在CPU上運(yùn)行的一個(gè)線程將共享對(duì)象讀入其CPU緩存并進(jìn)行修改。只要未將CPU緩存刷新回主存儲(chǔ)器,在其他CPU上運(yùn)行的線程就看不到共享對(duì)象的更改版本。

下圖說(shuō)明了這種情況,在左CPU上運(yùn)行的一個(gè)線程將共享對(duì)象復(fù)制到其CPU緩存中,并將其count變量更改為2。在右CPU上運(yùn)行的其他線程看不到此更改,因?yàn)樯形磳ount更新寫(xiě)回主內(nèi)存。

當(dāng)然這個(gè)問(wèn)題可以使用volatile關(guān)鍵字來(lái)解決。

競(jìng)爭(zhēng)條件

如果兩個(gè)或多個(gè)線程共享一個(gè)對(duì)象,并且一個(gè)以上的線程更新該共享對(duì)象中的變量,則可能會(huì)發(fā)生競(jìng)爭(zhēng)條件。

假如線程A將共享對(duì)象的變量count讀入其CPU緩存中,而線程B執(zhí)行同樣操作,但是它位于不同的CPU緩存中?,F(xiàn)在,線程A加一個(gè)要計(jì)數(shù),線程B也執(zhí)行相同的操作?,F(xiàn)在count已增加兩次,在每個(gè)CPU高速緩存中增加一次。

如果這些增加是順序執(zhí)行的,則變量計(jì)數(shù)將增加兩次,并將原始值+2寫(xiě)回到主存儲(chǔ)器中。

但是,這兩個(gè)增量是在沒(méi)有同步的情況下并發(fā)執(zhí)行的。不管線程A和B中哪個(gè)線程將其更新后的版本寫(xiě)回主內(nèi)存,盡管有兩個(gè)增量,但更新后的值僅比原始值高1。

該圖說(shuō)明了如上所述的競(jìng)爭(zhēng)條件問(wèn)題的發(fā)生:

這個(gè)問(wèn)題可以使用synchronized關(guān)鍵字來(lái)解決。

總結(jié)

到此這篇關(guān)于Java內(nèi)存模型的文章就介紹到這了,更多相關(guān)Java內(nèi)存模型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java代碼中如何去掉煩人的“!=null”

    Java代碼中如何去掉煩人的“!=null”

    這篇文章主要介紹了Java代碼中去掉煩人的“!=null”,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • MyBatis使用<foreach>標(biāo)簽報(bào)錯(cuò)問(wèn)題及解決

    MyBatis使用<foreach>標(biāo)簽報(bào)錯(cuò)問(wèn)題及解決

    這篇文章主要介紹了MyBatis使用<foreach>標(biāo)簽報(bào)錯(cuò)問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Java?Web中Ajax技術(shù)使用方法介紹

    Java?Web中Ajax技術(shù)使用方法介紹

    ajax技術(shù)是使頁(yè)面能局部刷新的一種技術(shù),下面這篇文章主要給大家介紹了關(guān)于JavaWeb之Ajax的基本使用與實(shí)戰(zhàn)案例的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • Java接口和抽象類(lèi)原理詳解

    Java接口和抽象類(lèi)原理詳解

    這篇文章主要介紹了Java接口和抽象類(lèi)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Eclipse項(xiàng)目有紅感嘆號(hào)的解決方法

    Eclipse項(xiàng)目有紅感嘆號(hào)的解決方法

    這篇文章主要為大家詳細(xì)介紹了Eclipse項(xiàng)目有紅感嘆號(hào)的解決方法,給出了Eclipse項(xiàng)目有紅感嘆號(hào)的原因,以及如何解決?,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Java操作mongodb增刪改查的基本操作實(shí)戰(zhàn)指南

    Java操作mongodb增刪改查的基本操作實(shí)戰(zhàn)指南

    MongoDB是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù),由c++語(yǔ)言編寫(xiě),旨在為WEB應(yīng)用提供可擴(kuò)展的高性能數(shù)據(jù)存儲(chǔ)解決方案,下面這篇文章主要給大家介紹了關(guān)于Java操作mongodb增刪改查的基本操作實(shí)戰(zhàn)指南,需要的朋友可以參考下
    2023-05-05
  • 全面解析Hibernate關(guān)聯(lián)操作、查詢操作、高級(jí)特性、并發(fā)處理機(jī)制

    全面解析Hibernate關(guān)聯(lián)操作、查詢操作、高級(jí)特性、并發(fā)處理機(jī)制

    這篇文章主要介紹了全面解析Hibernate關(guān)聯(lián)操作、查詢操作、高級(jí)特性、并發(fā)處理機(jī)制的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-06-06
  • Java 如何從list中刪除符合條件的數(shù)據(jù)

    Java 如何從list中刪除符合條件的數(shù)據(jù)

    這篇文章主要介紹了Java 如何從list中刪除符合條件的數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Spring@Value屬性注入使用方法解析

    Spring@Value屬性注入使用方法解析

    這篇文章主要介紹了Spring@Value屬性注入使用方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • 老生常談Java中instanceof關(guān)鍵字的理解

    老生常談Java中instanceof關(guān)鍵字的理解

    java 中的instanceof 運(yùn)算符是用來(lái)在運(yùn)行時(shí)指出對(duì)象是否是特定類(lèi)的一個(gè)實(shí)例。這篇文章主要介紹了老生常談Java中instanceof關(guān)鍵字的理解,需要的朋友可以參考下
    2018-10-10

最新評(píng)論

金阳县| 韶关市| 莱州市| 乳山市| 阿巴嘎旗| 涟源市| 崇左市| 华容县| 茂名市| 于都县| 突泉县| 高阳县| 建昌县| 威信县| 太仓市| 绥德县| 凤台县| 女性| 望城县| 临夏县| 鹤岗市| 通城县| 察雅县| 东港市| 常德市| 贺兰县| 神木县| 长子县| 太和县| 寿宁县| 宿松县| 肃宁县| 洪洞县| 东光县| 昌黎县| 清涧县| 锦屏县| 遵义县| 长岛县| 垣曲县| 广安市|