JMM初學

文章目錄

  • 1,線程間的同步和通信
    • 1.1, 共享內存并發模型 (Shared Memory Model)
      • 線程通信機制
      • 線程同步機制
      • 特點
    • 1.2, 消息傳遞并發模型 (Message Passing Model)
      • 線程通信機制
      • 線程同步機制
      • 特點
    • 適用場景對比
  • 2,Java內存模型JMM
    • 2.0,Java內存模型的基礎
      • (1)內存屏障
      • (2)happens before
    • 2.1,內存可見性
      • (1)為什么會出現內存可見性問題?
      • (2)內存可見性的發生過程
      • (3)JMM如何保證內存可見性
    • 2.2,JMM與重排序
      • (1)指令重排序的類型
      • (2)JMM如何限制重排序
    • 2.3順序一致性模型
      • (1)核心定義
      • (2)同步程序的順序一致性效果

  • 根據 JMM 的規定,線程對共享變量的所有操作都必須在自己的本地內存中進行,不能直接從主存中讀取
  • Java 運行時內存區域和JMM
    • Java 運行時內存區域描述的是在 JVM 運行時,如何將內存劃分為不同的區域,并且每個區域的功能和工作機制。
    • Java 內存模型 (JMM) 主要針對的是多線程環境下,如何在主內存與工作內存之間安全地執行操作。它涵蓋的主題包括變量的可見性、指令重排、原子操作等,旨在解決由于多線程并發編程帶來的一些問題。(可見性,有序性,原子性)
  • 指令重排是為了提高 CPU 性能,但是可能會導致一些問題,比如多線程環境下的內存可見性問題。

1,線程間的同步和通信

并發編程的線程之間存在兩個問題:

  • 線程間如何通信?即:線程之間以何種機制來交換信息

  • 線程間如何同步?即:線程以何種機制來控制不同線程間發生的相對順序

有兩種并發模型可以解決這兩個問題:

  • 消息傳遞并發模型
  • 共享內存并發模型

1.1, 共享內存并發模型 (Shared Memory Model)

Java主要采用這種模型

線程通信機制

  • 通過共享內存進行通信
  • 線程之間共享程序的公共狀態(變量、對象等)
  • 線程通過讀寫共享內存中的變量來隱式通信

線程同步機制

  • 使用顯式同步原語控制執行順序
  • 主要同步手段:
    • 鎖(synchronized, Lock)
    • volatile變量
    • 原子變量(AtomicInteger等)
    • 內存屏障

特點

  • 通信是隱式的(通過內存訪問)
  • 需要程序員顯式控制同步
  • 容易出現競態條件、死鎖等問題

1.2, 消息傳遞并發模型 (Message Passing Model)

如Go語言的channel、Actor模型

線程通信機制

  • 通過發送和接收消息進行顯式通信
  • 線程/進程間沒有共享狀態
  • 消息通道是唯一的通信媒介

線程同步機制

  • 通信本身就是同步的(發送和接收操作)
  • 常見實現方式:
    • 同步消息傳遞(發送者阻塞直到消息被接收)
    • 異步消息傳遞+消息隊列
    • CSP(Communicating Sequential Processes)模型

特點

  • 通信是顯式的(明確的send/receive操作)
  • 同步內建于通信機制中
  • 避免了共享內存帶來的許多問題

適用場景對比

場景推薦模型原因
分布式系統消息傳遞天然適合網絡通信
單機高并發共享內存性能更高
簡單并發任務消息傳遞更易實現和維護
復雜數據共享共享內存更高效的數據訪問
容錯系統消息傳遞更好的隔離性和恢復能力
實時系統共享內存更低延遲

2,Java內存模型JMM

Java內存模型(Java Memory Model, JMM)是Java虛擬機規范中定義的一種內存訪問規范,它是一種抽象概念,包含緩存、寫緩沖區、寄存器等。它規定了多線程環境下如何正確地訪問共享變量,以及線程之間如何通過內存進行通信。即解決上述的“線程間如何通信”和“線程間如何同步兩個問題”。保證多線程環境下的可見性、有序性和原子性。

JMM解決的三大問題

問題類型描述JMM解決方案
可見性一個線程修改共享變量后其他線程立即可見volatile、synchronized、final
有序性指令執行順序與代碼順序一致happens-before、內存屏障
原子性操作不可中斷synchronized、原子類

2.0,Java內存模型的基礎

(1)內存屏障

屏障類型作用
LoadLoad禁止 Load1Load2 重排序
StoreStore禁止 Store1Store2 重排序
LoadStore禁止 Load 和后續 Store 重排序
StoreLoad禁止 Store 和后續 Load 重排序

eg:LoadLoad屏障

確保 Load1 先于 Load2 執行,防止讀操作重排序。

StoreLoad 屏障(全能屏障)

  • 作用
    • 禁止 Store 和后續 Load 重排序。
    • 強制刷新所有寫操作到主內存,并 使其他 CPU 緩存失效
  • 開銷最大,但能保證最強的內存一致性。‘

(2)happens before

Happens-Before 是 Java 內存模型(JMM)的核心概念,它定義了多線程環境下操作之間的可見性保證執行順序約束,使開發者能夠在不深入理解底層內存屏障的情況下編寫正確的并發程序。

Happens-Before 描述的是兩個操作之間的偏序關系

  • 如果操作 A happens-before 操作 B,那么:
    • A 的執行結果對 B 可見
    • A 的代碼順序在 B 之前

📌 注意:Happens-Before 并不一定代表時間上的先后,而是可見性保證

happens-before的六大規則

  • 程序順序規則同一線程中的操作,按照代碼順序 happens-before。
  • 監視器鎖規則解鎖(unlock) happens-before 后續的加鎖(lock)
  • volatile 變量規則volatile 寫 happens-before 后續的 volatile 讀
  • 線程啟動規則Thread.start() happens-before 該線程的所有操作
  • 線程終止規則線程的所有操作 happens-before 其他線程檢測到它終止(如 t.join() )。
  • 傳遞性規則:如果 A happens-before B,且 B happens-before C,則 A happens-before C

2.1,內存可見性

內存可見性(Memory Visibility)是多線程編程中的一個核心概念,指的是當一個線程修改了共享變量的值后,其他線程能否立即看到這個修改。如果修改后的值不能及時被其他線程觀察到,就會導致內存可見性問題,從而引發程序邏輯錯誤。

什么是共享變量共享變量是指在多線程環境下可以被多個線程共同訪問和修改的變量。對于每一個線程來說,棧都是私有的,而堆是共有的。也就是說,在棧中的變量(局部變量、方法定義的參數、異常處理的參數)不會在線程之間共享,也就不會有內存可見性的問題,也不受內存模型的影響。而在堆中的變量是共享的,一般稱之為共享變量。所以,內存可見性針對的是堆中的共享變量。

(1)為什么會出現內存可見性問題?

現代計算機和 JVM 為了提高性能,會采用以下優化策略,導致內存可見性問題:

(1) CPU 緩存架構

  • CPU 不會直接讀寫主內存(RAM),而是通過**多級緩存(L1/L2/L3 Cache)**來提高訪問速度。
  • 每個 CPU 核心有自己的緩存,線程運行時可能只更新自己的緩存,而不會立即同步到主內存。
  • 因此,一個線程的修改可能對其他線程不可見

(2) 指令重排序(Reordering)

  • 編譯器優化:JIT 編譯器可能會調整指令順序以提高性能。

  • CPU 亂序執行:CPU 可能會改變指令的執行順序(只要不影響單線程語義)。

  • 這可能導致線程 A 的修改操作被延遲或亂序執行,導致線程 B 看到的數據不一致。

    public class ReorderingProblem {
    private static int x = 0;
    private static int y = 0;
    private static boolean ready = false;

    public static void main(String[] args) {Thread writer = new Thread(() -> {x = 1;y = 2;ready = true;  // 可能被重排序到前面});Thread reader = new Thread(() -> {while (!ready);  // 等待ready=trueSystem.out.println("x=" + x + ", y=" + y);  // 可能輸出x=0, y=2});writer.start();reader.start();
    }
    

    }

由于指令重排序問題,可能會ready = true 可能先于 x = 1 執行,導致 reader 線程看到 x=0,但 y=2

(3) 工作內存(Working Memory)抽象

  • JMM(Java 內存模型)規定,每個線程有自己的工作內存(可以理解為 CPU 緩存 + 寄存器 + 寫緩沖區)。
  • 線程操作共享變量時,先在工作內存中修改,再同步回主內存,這可能導致其他線程看不到最新值。

(2)內存可見性的發生過程

在這里插入圖片描述

從圖中可以看出:

  1. 所有的共享變量都存在主存中。
  2. 每個線程都保存了一份該線程使用到的共享變量的副本。
  3. 如果線程 A 與線程 B 之間要通信的話,必須經歷下面 2 個步驟:
    1. 線程 A 將本地內存 A 中更新過的共享變量刷新到主存中去。
    2. 線程 B 到主存中去讀取線程 A 之前已經更新過的共享變量。

所以,線程 A 無法直接訪問線程 B 的工作內存,線程間通信必須經過主存。

注意,根據 JMM 的規定,線程對共享變量的所有操作都必須在自己的本地內存中進行,不能直接從主存中讀取

所以線程 B 并不是直接去主存中讀取共享變量的值,而是先在本地內存 B 中找到這個共享變量,發現這個共享變量已經被更新了,然后本地內存 B 去主存中讀取這個共享變量的新值,并拷貝到本地內存 B 中,最后線程 B 再讀取本地內存 B 中的新值。

(3)JMM如何保證內存可見性

Java內存模型(JMM)的核心作用之一就是解決"如何知道共享變量被其他線程更新了"這個問題。

JMM 通過控制主存與每個線程的本地內存之間的交互,來提供內存可見性保證

Java 中的 volatile 關鍵字可以保證多線程操作共享變量的可見性以及禁止指令重排序,synchronized 關鍵字不僅保證可見性,同時也保證了原子性(互斥性)。

在更底層,JMM 通過內存屏障來實現內存的可見性以及禁止重排序。為了程序員更方便地理解,設計者提出了 happens-before 的概念,它更加簡單易懂,從而避免了程序員為了理解內存可見性而去學習復雜的重排序規則,以及這些規則的具體實現方法。

2.2,JMM與重排序

Java內存模型(JMM)的一個重要方面就是管理指令重排序(Reordering),它定義了在多線程環境下哪些重排序是被允許的,哪些是被禁止的。理解這一點對編寫正確的并發程序至關重要。

(1)指令重排序的類型

  1. 編譯器優化的重排序

編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執行順序

  1. 指令級并行的重排序

現代處理器采用指令級并行技術(ILP)來將多條指令重疊執行

  1. 內存系統的重排序

由于處理器使用緩存和讀寫緩沖區,使得加載和存儲操作看上去可能是在亂序執行

(2)JMM如何限制重排序

JMM通過以下幾種機制來限制重排序:

  1. happens-before規則

定義了一系列天然的happens-before關系,在這些關系下禁止重排序:

  • 程序順序規則
  • 監視器鎖規則
  • volatile變量規則
  • 線程啟動/終止規則
  • 傳遞性規則
  1. 內存屏障(Memory Barrier)

JMM在關鍵位置插入內存屏障指令來禁止特定類型的重排序:

屏障類型作用
LoadLoad禁止Load1與Load2重排序
StoreStore禁止Store1與Store2重排序
LoadStore禁止Load與后續Store重排序
StoreLoad全能屏障,禁止Store與后續Load重排序(開銷最大)
  1. 特殊關鍵字語義
  • volatile:禁止與相鄰指令重排序
  • final:保證正確構造后的對象對所有線程可見
  • synchronized:進入/退出時隱含內存屏障

2.3順序一致性模型

(1)核心定義

順序一致性模型必須滿足兩個基本條件:

  1. 程序順序保留:每個線程內部的操作必須按照該線程的程序代碼順序執行。(不允許重排序)
  2. 全局內存順序:所有線程看到的整個系統的操作執行順序必須一致

順序一致性模型雖然理論上完美,但硬件上難以實現,但Java等語言可以提供近似保證。

(2)同步程序的順序一致性效果

在并發編程中,通過同步機制可以使程序表現出順序一致性的內存效果,即使底層硬件和編譯器可能進行各種優化。

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

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

相關文章

【動手學MCP從0到1】2.5 MCP中的Context日志輸出、進度匯報和服務端調用客戶端的大模型項目實現步驟詳解

MCP中的Context 1. Context2. 日志輸出2.1 服務端2.2 客戶端2.2.1 客戶端代碼調試2.2.2 客戶端全部代碼 3. 進度匯報3.1 服務端3.2 客戶端3.2.1 客戶端代碼調試3.2.2 客戶端全部代碼 4. 模型調用4.1 服務端4.2 客戶端4.2.1 客戶端代碼調試4.2.2 客戶端全部代碼 1. Context Con…

QT自定義資源管理器

使用qt 和 C實現。還在優化中 項目地址:GitHub - Linda1226/FileResourceManager: 自定義資源管理器 有問題可以交流

[華為eNSP] OSPF綜合實驗

目錄 配置流程 畫出拓撲圖、標注重要接口IP 配置客戶端IP 配置服務端IP 配置服務器服務 配置路由器基本信息:名稱和接口IP 配置路由器ospf協議 測試結果 通過配置OSPF路由協議,實現跨多路由器的網絡互通,并驗證終端設備的訪問能力。 …

如何把本地服務器變成公網服務器?內網ip網址轉換到外網連接訪問

? 內網IP只能在本地內部網絡連接訪問,當本地搭建服務器部署好相關網站或應用后,在局域網內可以通過內網IP訪問,但在外網是無法直接訪問異地內網IP端口應用的,只有公網IP和域名才能實現互聯網上的訪問。那么需要如何把本地服務器變…

Linux-文件管理及歸檔壓縮

1.根下的目錄作用說明: /:Linux系統中所有的文件都在根下/bin:(二進制命令目錄)存放常用的用戶命令/boot:系統啟動時的引導文件(內核的引導配置文件,grub配置文件,內核配置文件) 例…

從零開始的python學習(七)P95+P96+P97+P98+P99+P100+P101

本文章記錄觀看B站python教程學習筆記和實踐感悟,視頻鏈接:【花了2萬多買的Python教程全套,現在分享給大家,入門到精通(Python全棧開發教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p6&share_sourcecopy_web&v…

Linux 查找特定字符詳細講解

CentOS 7 中使用 grep 查找特定字符詳細筆記? 一、grep 命令概述? grep 全稱為 Global Regular Expression Print,即全局正則表達式打印,是 CentOS 7 系統中用于文本搜索的核心工具。它基于正則表達式或固定字符串,在文件、標準輸入流中進…

uniappx插件nutpi-idcard 開發與使用指南(適配鴻蒙)

uniappx插件nutpi-idcard 開發與使用指南(適配鴻蒙) 前言 nutpi-idcard 是一個基于 UTS (uni-app TypeScript Syntax) 開發的 uni-app 插件適配鴻蒙,主要用于解析身份證號碼,提取其中的關鍵信息,如地區、出生日期、性…

Grafana-ECharts應用講解(玫瑰圖示例)

工具: MySQL 數據庫 MySQL Workbench 數據庫管理工具(方便編輯數據) Grafana v11.5.2 Business Charts 6.6(原 Echarts插件) 安裝 安裝 MySQL社區版安裝 MySQL Workbench安裝 Grafana在 Grafana 插件中搜索 Business Charts 進行安裝以上安裝步驟網上教程很多,自行搜…

React狀態管理Context API + useReducer

在 React 中,Context API useReducer 是一種輕量級的狀態管理方案,適合中小型應用或需要跨組件共享復雜狀態的場景。它避免了 Redux 的繁瑣配置,同時提供了清晰的狀態更新邏輯。 1. 基本使用步驟 (1) 定義 Reducer 類似于 Redux 的 reduce…

3 個優質的終端 GitHub 開源工具

1、Oh My Zsh Oh My Zsh 是一個幫助你管理和美化 zsh 終端的開源工具。它讓你的終端更炫酷、更高效。安裝后,你可以快速使用各種插件和主題,比如常見的 git 命令簡化、支持多種編程語言工具等,每次打開終端都會有驚喜。無論你是開發者還是普…

無人機巡檢智能邊緣計算終端技術方案??——基于EFISH-SCB-RK3588工控機/SAIL-RK3588核心板的國產化替代方案?

一、方案核心價值? ?實時AI處理?:6TOPS NPU實現無人機影像的實時缺陷檢測(延遲<50ms)?全國產化?:芯片、操作系統、算法工具鏈100%自主可控?極端環境適配?:-40℃~85℃穩定運行,IP65防護等…

SpringAI 1.0.0 正式版——利用Redis存儲會話(ChatMemory)

官方文檔:Chat Memory :: Spring AI Reference 1. 引言 SpringAI 1.0.0 改動了很多地方,本文根據官方的InMemoryChatMemoryRepository實現了自定義的RedisChatMemoryRepository,并使用MessageWindowChatMemory創建ChatMemory 2. 實現 2.1.…

RFC8489-STUN

0. 學習參考 RFC5389 中文翻譯 中文RFC RFC文檔 RFC翻譯 RFC中文版 RFC 5389:NAT 的會話遍歷實用程序 (STUN) --- RFC 5389: Session Traversal Utilities for NAT (STUN) 1. RFC 3489的演變 自 RFC 3489 發布以來的經驗發現,…

開始在本地部署自己的 Gitea 服務器

0.簡介 在軟件開發和團隊協作中,代碼管理是至關重要的環節。筆者一直使用gitblit管理自己的倉庫。然鵝,這個軟件已經很久沒有更新了。經過多方考察,發現Gitea 是一款輕量級的開源代碼托管平臺,具有易于部署、資源占用少、功能豐富…

Xsens-AAA工作室品質,為動畫師準備

每一幀都講述著一個故事,當動作真實呈現時,故事便鮮活起來。我們打造并改進了 Xsens Animate,助力專業人士突破數字動畫的界限。 通過升級后的 Xsens Animate,您可以獲得女性和男性解剖模型以及更精確的運動引擎,從一…

嵌入(Embedding)技術的實現原理與應用場景解析

嵌入(Embedding)技術的實現原理與應用場景解析 引言:從One-Hot到語義空間 在自然語言處理的演進歷程中,嵌入技術(Embedding)的誕生標志著一個重要轉折點——它讓離散的符號表示突破了維度詛咒&#xff0c…

金倉數據庫征文-金倉KES數據同步優化實踐:邏輯解碼與增量同步

目錄 一.同步場景與方案選型 二.什么是KES 三.同步環境配置 1.前置條件驗證 2.邏輯解碼配置 四.同步實施與問題排查 1.結構映射規則 2.增量數據捕獲 3.數據一致性校驗 五.性能調優實踐 1.同步線程優化 2.批量提交優化 3.資源監控指標 六.典型場景解決方案 1.雙向…

開源語義分割工具箱mmsegmentation基于Lovedata數據集訓練模型

開源語義分割工具箱mmsegmentation安裝環境 文章目錄 1、下載數據集2、整理數據集3、下載預訓練模型4、測試5、訓練模型參考官方數據處理步驟 https://github.com/open-mmlab/mmsegmentation/blob/main/docs/zh_cn/user_guides/2_dataset_prepare.md#loveda 數據集類別標簽:…

Python概率統計可視化——概率分布、假設檢驗與分子運動模型

Python概率統計可視化——概率分布、假設檢驗與分子運動模型 前言 概率統計作為描述不確定性和隨機現象的數學工具,廣泛應用于物理學、生物學、經濟學等領域。然而,抽象的概率分布和統計推斷過程往往難以直觀理解。可視化技術通過將概率密度、假設檢驗邏…