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

Java內存模型及其作用詳解

 更新時間:2024年04月03日 10:45:24   作者:牽著貓散步的鼠鼠  
在現(xiàn)代計算機系統(tǒng)中,尤其是多處理器架構下,每個處理器都有自己的高速緩存,而主內存(RAM)是所有處理器共享的數(shù)據(jù)存儲區(qū)域,這篇文章主要介紹了深入理解Java內存模型及其作用,需要的朋友可以參考下

1.前言

當問到 Java 內存模型的時候,一定要注意,Java 內存模型(Java Memory Model,JMM)它和 JVM 內存布局(JVM 運行時數(shù)據(jù)區(qū)域)是不一樣的,它們是兩個完全不同的概念。

2.為什么要有 Java 內存模型?

Java 內存模型存在的原因在于解決多線程環(huán)境下并發(fā)執(zhí)行時的內存可見性和一致性問題。在現(xiàn)代計算機系統(tǒng)中,尤其是多處理器架構下,每個處理器都有自己的高速緩存,而主內存(RAM)是所有處理器共享的數(shù)據(jù)存儲區(qū)域。當多個線程同時訪問和修改同一塊共享數(shù)據(jù)時,如果沒有適當?shù)耐綑C制,就可能導致以下問題:

  • 可見性:一個線程對共享變量所做的修改可能不會立即反映到另一個線程的視角中,因為這些修改可能只存在于本地緩存中,并未刷新回主內存。
  • 有序性:編譯器和處理器為了優(yōu)化性能,可能會對指令進行重排序,這可能導致程序在單線程環(huán)境中看似按照源代碼順序執(zhí)行,但在多線程環(huán)境中的實際執(zhí)行順序卻與預期不同。
  • 原子性:即使是最簡單的讀取或賦值操作,在硬件層面也不一定保證是原子性的,即在沒有同步的情況下,多線程下可能看到操作只執(zhí)行了一部分的結果。

Java 內存模型通過定義一套規(guī)則來規(guī)范并限制編譯器、運行時以及處理器對內存訪問的重排序行為,確保了多線程間的交互具有明確的語義。它規(guī)定了共享變量的訪問規(guī)則、提供了 happens-before 原則以及 volatile 關鍵字、synchronized 等工具來實現(xiàn)內存可見性和一致性的保障。這樣,程序員在編寫并發(fā)代碼時,可以依據(jù)這些規(guī)則來確保代碼的正確執(zhí)行,從而避免由于多線程帶來的不確定性和錯誤。

如果沒有 Java 內存模型就會出現(xiàn)以下兩大問題:

  • CPU 和 內存一致性問題。
  • 指令重排序問題。

具體內容如下。

2.1 一致性問題

要講明白緩存一致性問題,要從計算機的內存結構說起,它的結構是這樣的: 

 所以從上面可以看出計算機的重要組成部分包含以下內容:

  • CPU
  • CPU 寄存器:也叫 L1 緩存,一級緩存。
  • CPU 高速緩存:也叫 L2 緩存,二級緩存。
  • (主)內存

當然,部分高端機器還有 L3 三級緩存。

由于主內存與 CPU 處理器的運算能力之間有數(shù)量級的差距,所以在傳統(tǒng)計算機內存架構中會引入高速緩存(L2)來作為主存和處理器之間的緩沖,CPU 將常用的數(shù)據(jù)放在高速緩存中,運算結束后 CPU 再講運算結果同步到主內存中,這樣就會導致多個線程在進行操作和同步時,導致 CPU 緩存和主內存數(shù)據(jù)不一致的問題。

2.2 重排序問題

由于有 JIT(Just In Time,即時編譯)技術的存在,它可能會對代碼進行優(yōu)化,比如將原本執(zhí)行順序為 a -> b -> c 的流程,“優(yōu)化”成 a -> c -> b 了,但這樣優(yōu)化之后,可能會導致我們的程序在某些場景執(zhí)行出錯,比如單例模式雙重效驗鎖的場景,這就是典型的好心辦壞事的事例。

3.Java 內存模型的定義

Java 內存模型(Java Memory Model,簡稱 JMM)是一種規(guī)范,它定義了 Java 虛擬機(JVM)在計算機內存(RAM)中的工作方式,即規(guī)范了 Java 虛擬機與計算機內存之間是如何協(xié)同工作的。具體來說,它規(guī)定了一個線程如何和何時可以看到其他線程修改過的共享變量的值,以及在必須時如何同步地訪問共享變量。

4.規(guī)范內容

Java 內存模型主要包括以下內容:

  • 主內存(Main Memory):所有線程共享的內存區(qū)域,包含了對象的字段、方法和運行時常量池等數(shù)據(jù)。
  • 工作內存(Working Memory):每個線程擁有自己的工作內存,用于存儲主內存中的數(shù)據(jù)的副本,線程只能直接操作工作內存中的數(shù)據(jù)。
  • 內存間交互操作:線程通過讀取和寫入操作與主內存進行交互。讀操作將數(shù)據(jù)從主內存復制到工作內存,寫操作將修改后的數(shù)據(jù)刷新到主內存。
  • 原子性(Atomicity):JMM 保證基本數(shù)據(jù)類型(如 int、long)的讀寫操作具有原子性,即不會被其他線程干擾,保證操作的完整性。
  • 可見性(Visibility):JMM 確保一個線程對共享變量的修改對其他線程可見。這意味著一個線程在工作內存中修改了數(shù)據(jù)后,必須將最新的數(shù)據(jù)刷新到主內存,以便其他線程可以讀取到更新后的數(shù)據(jù)。
  • 有序性(Ordering):JMM 保證程序的執(zhí)行順序按照一定的規(guī)則進行,不會出現(xiàn)隨機的重排序現(xiàn)象。這包括了編譯器重排序、處理器重排序和內存重排序等。

Java 內存模型通過以上規(guī)則和語義,提供了一種統(tǒng)一的內存訪問方式,使得多線程程序的行為可預測、可理解,并幫助開發(fā)者編寫正確和高效的多線程代碼。開發(fā)者可以利用 JMM 提供的同步機制(如關鍵字 volatile、synchronized、Lock 等)來實現(xiàn)線程之間的同步和通信,以確保線程安全和數(shù)據(jù)一致性。

內存模型的簡單執(zhí)行示例圖如下: 

4.1 主內存和工作內存交互規(guī)范

為了更好的控制主內存和本地內存的交互,Java 內存模型定義了八種操作來實現(xiàn)(以下內容只需要簡單了解即可):

  • lock(鎖定):作用于主內存的變量,把一個變量標識為一條線程獨占狀態(tài)。
  • unlock(解鎖):作用于主內存變量,把一個處于鎖定狀態(tài)的變量釋放出來,釋放后的變量才可以被其他線程鎖定。
  • read(讀?。鹤饔糜谥鲀却孀兞浚岩粋€變量值從主內存?zhèn)鬏數(shù)骄€程的工作內存中,以便隨后的 load 動作使用
  • load(載入):作用于工作內存的變量,它把 read 操作從主內存中得到的變量值放入工作內存的變量副本中。
  • use(使用):作用于工作內存的變量,把工作內存中的一個變量值傳遞給執(zhí)行引擎,每當虛擬機遇到一個需要使用變量的值的字節(jié)碼指令時將會執(zhí)行這個操作。
  • assign(賦值):作用于工作內存的變量,它把一個從執(zhí)行引擎接收到的值賦值給工作內存的變量,每當虛擬機遇到一個給變量賦值的字節(jié)碼指令時執(zhí)行這個操作。
  • store(存儲):作用于工作內存的變量,把工作內存中的一個變量的值傳送到主內存中,以便隨后的write的操作。
  • write(寫入):作用于主內存的變量,它把 store 操作從工作內存中一個變量的值傳送到主內存的變量中。

PS:工作內存也就是本地內存的意思。

4.2 什么是 happens-before 原則?

happens-before(先行發(fā)生)原則是 Java 內存模型中定義的用于保證多線程環(huán)境下操作執(zhí)行順序和可見性的一種重要手段。

舉個例子來說,例如 A happens-before B,也就是 A 線程早于 B 線程執(zhí)行,那么 A happens-before B 可以保障以下兩項內容:

  • 可見性:B 讀取到 A 最新修改的值(通過內存屏障)。
  • 順序性:編譯器優(yōu)化、處理器重排序等因素不會影響先執(zhí)行 A 再執(zhí)行 B 的順序。

到此這篇關于深入理解Java內存模型及其作用的文章就介紹到這了,更多相關Java內存模型內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • String實例化及static final修飾符實現(xiàn)方法解析

    String實例化及static final修飾符實現(xiàn)方法解析

    這篇文章主要介紹了String實例化及static final修飾符實現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-09-09
  • java開發(fā)SpringBoot參數(shù)校驗過程示例教程

    java開發(fā)SpringBoot參數(shù)校驗過程示例教程

    這篇文章主要為大家介紹了SpringBoot如何進行參數(shù)校驗的過程示例詳解教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2021-10-10
  • 如何使用Spring Security實現(xiàn)用戶-角色-資源的權限控制

    如何使用Spring Security實現(xiàn)用戶-角色-資源的權限控制

    文章介紹了如何通過SpringSecurity實現(xiàn)用戶-角色-資源的權限管理,包括基于角色的請求控制、加載用戶角色信息、角色與資源的關聯(lián)等步驟,同時,提供了一些測試場景,以驗證權限控制是否正確,感興趣的朋友跟隨小編一起看看吧
    2024-10-10
  • java實現(xiàn)音頻轉文本的實現(xiàn)步驟

    java實現(xiàn)音頻轉文本的實現(xiàn)步驟

    本文主要介紹了java實現(xiàn)音頻轉文本的實現(xiàn)步驟,可以通過使用一些現(xiàn)成的庫或者API來實現(xiàn),文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2024-05-05
  • 使用java實現(xiàn)日志工具類分享

    使用java實現(xiàn)日志工具類分享

    這篇文章主要介紹的Java代碼工具類是用于書寫日志信息到指定的文件,并且具有刪除之前日志文件的功能,需要的朋友可以參考下
    2014-03-03
  • Java對象的復制三種方式(小結)

    Java對象的復制三種方式(小結)

    這篇文章主要介紹了Java對象的復制三種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • Springboot 如何實現(xiàn)filter攔截token驗證和跨域

    Springboot 如何實現(xiàn)filter攔截token驗證和跨域

    這篇文章主要介紹了Springboot 如何實現(xiàn)filter攔截token驗證和跨域操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • java微信小程序步數(shù)encryptedData和開放數(shù)據(jù)解密的實現(xiàn)

    java微信小程序步數(shù)encryptedData和開放數(shù)據(jù)解密的實現(xiàn)

    這篇文章主要介紹了java微信小程序步數(shù)encryptedData和開放數(shù)據(jù)解密的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • Java與WebUploader相結合實現(xiàn)文件上傳功能(實例代碼)

    Java與WebUploader相結合實現(xiàn)文件上傳功能(實例代碼)

    這篇文章主要介紹了Java結合WebUploader實現(xiàn)文件上傳功能,代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-03-03
  • 動態(tài)配置Spring Boot日志級別的全步驟

    動態(tài)配置Spring Boot日志級別的全步驟

    這篇文章主要給大家介紹了關于動態(tài)配置Spring Boot日志級別的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Spring Boot具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-04-04

最新評論