Java內存模型(Java Memory Model,JMM)

??????????JMM?? 是Java虛擬機(JVM)規范中定義的一組規則和規范,用于描述多線程環境下,Java程序中變量的訪問和修改行為,尤其是在并發編程中如何保證內存可見性原子性有序性。JMM 是 Java 并發編程的基石,它定義了線程之間如何通過內存進行交互,確保程序在不同平臺和處理器架構上具有一致的并發行為。(JMM保證了java并發編程的跨平臺)


一、JMM 的核心目標

JMM 的主要目標是解決多線程環境下的三個核心問題:

  1. ??原子性(Atomicity)?:?保證某些操作是不可分割的,要么全部執行,要么全部不執行,不會被其他線程干擾。

  2. ??可見性(Visibility)?:?當一個線程修改了共享變量的值后,其他線程能夠立即看到這個修改。

  3. ??有序性(Ordering)?:?程序執行的順序按照代碼的先后順序執行,避免指令重排序導致的邏輯錯誤。


二、JMM 的基本概念

1. 主內存與工作內存(重點)

JMM 抽象了線程與主內存之間的關系:

  • ??主內存(Main Memory)??:所有線程共享的內存區域,存儲所有的實例變量、靜態變量等。可以類比為計算機中的物理內存。

  • ??工作內存(Working Memory)??:每個線程都有自己的工作內存(類似于CPU的寄存器或緩存),線程從主內存中讀取變量到自己的工作內存中進行操作,操作完成后再將結果寫回主內存。工作內存是線程私有的,線程之間不能直接訪問彼此的工作內存。

2. 內存間的交互操作(不是重點)

JMM 定義了八種原子操作,用于線程與主內存之間的交互:

  1. ??lock(鎖定)??:作用于主內存的變量,將一個變量標識為一條線程獨占的狀態。
  2. ??unlock(解鎖)??:作用于主內存的變量,釋放一個變量的鎖定狀態。
  3. ??read(讀取)??:作用于主內存的變量,將一個變量的值從主內存傳輸到線程的工作內存,以便隨后的load操作。
  4. ??load(載入)??:作用于工作內存的變量,將read操作得到的值放入工作內存的變量副本中。
  5. ??use(使用)??:作用于工作內存的變量,將工作內存中的一個變量的值傳遞給執行引擎,每當虛擬機遇到一個需要使用變量的字節碼指令時就會執行這個操作。
  6. ??assign(賦值)??:作用于工作內存的變量,將執行引擎接收到的值賦給工作內存的變量,每當虛擬機遇到一個給變量賦值的字節碼指令時執行這個操作。
  7. ??store(存儲)??:作用于工作內存的變量,將工作內存中的一個變量的值傳送到主內存中,以便隨后的write操作。
  8. ??write(寫入)??:作用于主內存的變量,將store操作得到的值放入主內存的變量中。

這些操作必須按特定的規則組合執行,以確保內存操作的原子性、可見性和有序性。


三、JMM 與 Java 并發編程的關系

????????JMM 為 Java 并發編程提供了一套規范,確保在多線程環境下程序的行為是可預測和一致的。它通過定義內存屏障(Memory Barriers)、happens-before 關系等機制,來控制線程間的內存可見性和操作順序。

1. Happens-Before 原則

??Happens-Before?? 是 JMM 中的一個核心概念,用于判斷兩個操作之間的執行順序。如果操作A happens-before 操作B,那么操作A的結果對操作B可見,并且操作A在操作B之前執行。

JMM 定義了以下幾種 Happens-Before 關系:

  1. ??程序次序規則(Program Order Rule)??
    在同一個線程中,按照程序代碼的順序,前面的操作 happens-before 后面的操作。

  2. ??鎖定規則(Monitor Lock Rule)??
    一個線程解鎖操作 happens-before 另一個線程對同一個鎖的加鎖操作。

  3. ??volatile 變量規則(Volatile Variable Rule)??
    對一個 volatile 變量的寫操作 happens-before 后續對這個變量的讀操作。

  4. ??線程啟動規則(Thread Start Rule)??
    Thread 對象的?start()?方法調用 happens-before 啟動線程中的任何操作。

  5. ??線程終止規則(Thread Termination Rule)??
    線程中的任何操作 happens-before 其他線程檢測到該線程已經終止(通過?Thread.join()?方法或?Thread.isAlive()?返回 false)。

  6. ??線程中斷規則(Thread Interruption Rule)??
    對線程?interrupt()?方法的調用 happens-before 被中斷線程檢測到中斷事件(通過?Thread.interrupted()?或?Thread.isInterrupted())。

  7. ??對象終結規則(Finalizer Rule)??
    一個對象的初始化完成 happens-before 它的?finalize()?方法的開始。

  8. ??傳遞性(Transitivity)??
    如果操作A happens-before 操作B,且操作B happens-before 操作C,那么操作A happens-before 操作C。

??????????Happens-Before原則幫助開發者理解和推斷多線程程序中的內存可見性和操作順序,從而編寫出正確且高效的并發代碼。

2. 內存屏障(Memory Barriers)

????????雖然 JMM 在規范層面定義了 Happens-Before 關系,但在實際實現中,JVM 會通過插入??內存屏障??來保證這些關系。內存屏障是一種硬件或軟件機制,用于控制指令的執行順序和內存訪問的順序,防止指令重排序和保證內存可見性。

常見的 memory barriers 包括:

屏障類型作用說明
??LoadLoad 屏障??確保 Load1 的數據加載先于 Load2 及后續的加載操作防止 Load2 讀取到比 Load1 更舊的數據
??StoreStore 屏障??確保 Store1 的數據存儲先于 Store2 及后續的存儲操作防止 Store2 覆蓋 Store1 的數據
??LoadStore 屏障??確保 Load1 的數據加載先于 Store2 及后續的存儲操作防止 Store2 存儲的數據比 Load1 讀取的數據更舊
??StoreLoad 屏障??確保 Store1 的數據存儲先于 Load2 及后續的加載操作防止 Load2 讀取到比 Store1 更舊的數據(最耗性能)

????????這些屏障在不同的處理器架構上有不同的實現方式,JVM 會根據目標平臺插入相應的屏障指令,以保證 JMM 的語義。


四、JMM 與 Java 關鍵字的關系

????????Java 提供了一些關鍵字和工具來幫助開發者控制內存可見性和線程同步,這些機制在底層依賴于 JMM 的規范。

1.?volatile關鍵字

2.?synchronized關鍵字?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/91796.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/91796.shtml
英文地址,請注明出處:http://en.pswp.cn/web/91796.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【swoole Windows 開發(swoole-cli 開發 hyperf)】

先前swoole在Windows平臺的開發體驗極差,如果在Windows開發swoole的東西可以用docker或者虛擬機,遠程開發,體驗比較好的是直接Mac或者Linux系統開發。但是作為window平臺的釘子戶表示我窮。swoole之前已經推出了cygwin64編譯成winwods版本的方…

興達餐飲 酒店 進銷存管理系統軟件

興達餐飲 酒店 進銷存管理系統軟件

Seal Report:一款免費開源的報表工具

Seal Report 是一款基于 C# 語言開發的開源報表工具,可以從各種數據庫或 NoSQL 數據源中生成日常報告,并且執行復雜的計劃任務。 功能特性 免費開源:源代碼托管在 GitHub 上,用戶可以自由使用、修改、甚至集成到自己的系統中&…

WebRTC 多媒體 SDP 示例與解析

webRTC中的SDP的Bundlle可能包含一個或者多個媒體塊(媒體描述, 源碼對應類ContentInfo),從 m 開始到下一個 m 行(或 SDP 結束)之間的所有屬性(包括 a)都屬于同一個媒體塊(media sect…

SpringBoot 啟動富文本文字更改

正常來說 SpringBoot啟動時候,展示的文字是這個 、 主播這邊想要換一個樣式,換一個自己自定義的文字 這邊換成了自己的博客名字 具體實現操作如下 在項目目錄 resources下創建一個名字為banner.txt的文本,這是SpringBoot啟動的時候尋找的…

基于結構熵權-云模型的鑄鐵浴缸生產工藝安全評價

一、評價模型核心思想 結構熵權法 解決傳統熵權法忽略指標間結構關系的問題,通過指標層次網絡計算權重。 步驟: 構建工藝安全評價指標體系(樹狀/網絡結構) 計算同級指標間的影響度矩陣 引入修正熵權:wj=1?Ej∑(1?Ek)結構影響因子w_j = \frac{1 - E_j}{\sum (1 - E_k)} \…

[Linux]從零開始的vs code交叉調試arm Linux程序教程

一、前言 最近的項目中需要集成rknn的視覺識別,在這之前我并且沒有將rknn集成到自己項目的經驗。這里我需要在rknn原本demo的基礎上我還需要集成自己的業務代碼。但是又有一個問題,原本rknn我們都是使用交叉編譯編譯到開發板上的,并且我們還要…

視頻號私信自動化回復插件

給自己的瀏覽器插件又增加了視頻號斯信的自動化回復搜索:程序員老狼主體邏輯就是,不停的點擊打招呼和斯信那個tab切換查看有無小紅點,有小紅點的會話,就點擊。查看有無打招呼,有打招呼就點擊,抓取昵稱和內容…

Web前端實現銀河粒子流動特效的3種技術方案對比與實踐

文章目錄 前端實現銀河粒子流動特效的技術原理與實踐 引言:銀河粒子特效的技術背景與現狀 技術發展歷史 當前技術現狀 技術原理與實現方案 思維導圖:銀河粒子特效技術架構 1. CSS3實現方案 基礎實現代碼 性能優化技巧 2. Canvas 2D實現方案 基礎實現代碼 Canvas高級優化技術 …

Linux:告別Jammy,擁抱Noble!WSL Ubuntu 22.04 到 24.04 LTS 終極升級指南

大家好!如果大家和我一樣,是Windows Subsystem for Linux (WSL) 的忠實用戶,那么大家一定對Ubuntu在其中的表現印象深刻。我們中的許多人可能還在使用穩定可靠的Ubuntu 22.04 LTS (Jammy Jellyfish)。但現在,一個更令人興奮的時代…

江協科技STM32 11-1 SPI通信協議

本節課我們將繼續學習下一個通信協議,SPI。SPI通信和我們剛剛學習過的I2C通信差不多。兩個協議的設計目的都一樣都是實現主控芯片和各種外掛芯片之間的數據交流,有了數據交流的能力,我們的主控芯片就可以掛載并操縱各式各樣的外部芯片&#x…

預過濾環境光貼圖制作教程:第一步 - HDR 轉立方體貼圖

在基于物理的渲染(PBR)中,環境光貼圖是實現真實光照效果的核心組件之一。而將 HDR 全景圖轉換為立方體貼圖,是制作預過濾環境光貼圖的基礎步驟。本教程將詳細講解如何實現這一轉換過程。 什么是 HDR 轉立方體貼圖? HDR(高動態范圍)全景圖通常以等矩形投影(Equirectan…

02 深度學習介紹【動手學深度學習v2】| 學習筆記

1、intro自然語言處理雖然我們過去取得了很大的進展,但是實際上還是停留在感知層面。計算機視覺領域,因為圖片里面都是像素,像素很難用符號學來解釋,所以計算機視覺大部分是用概率模型或機器學習來做。深度學習它是機器學習的一種…

智能學號抽取系統V5.6.4重磅發布

告別隨機數,擁抱智能點名!—— 全新升級的“智能學號抽取系統V5.6.4”重磅發布! 摘要: 還在為課堂隨機提問、活動抽獎而手動翻名單、查表格而煩惱嗎?還在忍受傳統點名工具的簡陋和不智能嗎?今天&#xff0…

Leetcode-141.環形鏈表

dict和set 1. 結構上的區別:類型鍵(Key)值(Value)示例dict有有{a: 1, b: 2}set有沒有{a, b} dict 是**鍵值對(key-value)**的集合。set 是只有鍵(key)沒有值的一組唯一元…

調節步進電機速度時調PSC和調ARR的區別

在步進電機控制中,調節速度通常是通過改變脈沖頻率實現的。代碼中選擇調節ARR(Auto-Reload Register)而非PSC(Prescaler)的原因如下: 1. ARR 與 PSC 的核心區別 ? ARR(自動重載寄存器&#xff…

在 AKS 中運行 Azure DevOps 私有代理-1

簡介 配置 Azure DevOps 私有代理的傳統方法是將其部署在虛擬機 (VM) 上。然而,一個有趣的替代方案是利用 Azure Kubernetes 服務 (AKS) 來實現此目的。 本文將指導您如何使用 Helm Chart 在 AKS 集群中設置 Azure DevOps 私有代理,并提供該過程的分步說明。 在 AKS 中部署…

C# _Json數據

目錄 1、添加Json庫 2、數據序列化(對象轉 JSON)和反序列化(JSON 轉對象)操作 3、序列化 創建和讀取Json數據 創建Json數據 定義一個CreateJson方法 讀取 解析 Json數據 定義一個ReadJson方法 4、程序運行結果 在 C# 中&…

JavaScript 原始值與引用值

JavaScript 原始值與引用值 ECMAScript變量可以包含兩種不同類型的數據:原始值和引用值。 原始值(primitive value)就是最簡單的數據,引用值(reference value)則是由多個值構成的對象。 保存原始值的變量是…

linux中掛載磁盤和卸載

查找磁盤 找到你想要掛載的磁盤。可以使用lsblk或fdisk -l命令來查看系統中所有的磁盤和分區信息。 lsblk 對數據盤進行分區 在fdisk交互界面里,按以下步驟操作 fdisk /dev/vdb- 輸入n來創建新分區。 - 按照提示設置分區的起始扇區、結束扇區等信息,…