欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

內(nèi)存模型

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

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

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

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

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

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

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

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)對理解Java內(nèi)存模型也有幫助。簡單的硬件架構(gòu)圖如下:

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

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

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

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

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

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

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

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

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

  • 線程更新(寫入)到共享變量的可見性。
  • 讀取,檢查和寫入共享變量時的競爭條件。

對象的可見性

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

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

下圖說明了這種情況,在左CPU上運行的一個線程將共享對象復(fù)制到其CPU緩存中,并將其count變量更改為2。在右CPU上運行的其他線程看不到此更改,因為尚未將count更新寫回主內(nèi)存。

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

競爭條件

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

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

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

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

該圖說明了如上所述的競爭條件問題的發(fā)生:

這個問題可以使用synchronized關(guān)鍵字來解決。

總結(jié)

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

相關(guān)文章

  • 詳解Java中字符流與字節(jié)流的區(qū)別

    詳解Java中字符流與字節(jié)流的區(qū)別

    這篇文章主要介紹了詳解Java中字符流與字節(jié)流的區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • SpringBoot集成WebSocket遇到的問題及解決

    SpringBoot集成WebSocket遇到的問題及解決

    這篇文章主要介紹了SpringBoot集成WebSocket遇到的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。
    2023-07-07
  • Java WindowBuilder 安裝及基本使用的教程

    Java WindowBuilder 安裝及基本使用的教程

    這篇文章主要介紹了Java WindowBuilder 安裝及基本使用的教程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • IDEA報錯:Unable to save settings Failed to save settings

    IDEA報錯:Unable to save settings Failed to save settings

    這篇文章主要介紹了IDEA報錯:Unable to save settings Failed to save settings的相關(guān)知識,本文給大家分享問題原因及解決方案,需要的朋友可以參考下
    2020-09-09
  • Java?超詳細(xì)帶你掌握矩陣的運算

    Java?超詳細(xì)帶你掌握矩陣的運算

    在學(xué)習(xí)機(jī)器學(xué)習(xí)算法時,發(fā)現(xiàn)運用java?來實現(xiàn)有些算法代碼時,會有很大困難,其中有一點就是?java?本身并沒有矩陣運算的?api,所以進(jìn)行要實現(xiàn)矩陣運算就尤其復(fù)雜,讓我們一起了解矩陣的運算
    2022-03-03
  • Java多線程中線程池常見7個參數(shù)的詳解以及執(zhí)行流程

    Java多線程中線程池常見7個參數(shù)的詳解以及執(zhí)行流程

    本文主要介紹了Java多線程中線程池常見7個參數(shù)的詳解以及執(zhí)行流程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • JVM優(yōu)先級線程池做任務(wù)隊列的實現(xiàn)方法

    JVM優(yōu)先級線程池做任務(wù)隊列的實現(xiàn)方法

    這篇文章主要介紹了JVM優(yōu)先級線程池做任務(wù)隊列的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Java線程池隊列PriorityBlockingQueue原理分析

    Java線程池隊列PriorityBlockingQueue原理分析

    這篇文章主要介紹了Java線程池隊列PriorityBlockingQueue原理分析,PriorityBlockingQueue隊列是?JDK1.5?的時候出來的一個阻塞隊列,但是該隊列入隊的時候是不會阻塞的,永遠(yuǎn)會加到隊尾,需要的朋友可以參考下
    2023-12-12
  • Spring MVC參數(shù)校驗詳解(關(guān)于`@RequestBody`返回`400`)

    Spring MVC參數(shù)校驗詳解(關(guān)于`@RequestBody`返回`400`)

    這篇文章主要介紹了Spring MVC參數(shù)校驗的相關(guān)資料,主要是針對`@RequestBody`返回`400`的問題,文中通過示例代碼介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08
  • Hibernate批量處理海量數(shù)據(jù)的方法

    Hibernate批量處理海量數(shù)據(jù)的方法

    這篇文章主要介紹了Hibernate批量處理海量數(shù)據(jù)的方法,較為詳細(xì)的分析了Hibernate批量處理海量數(shù)據(jù)的原理與相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2016-03-03

最新評論