首頁 Java Java基礎 Java記憶體模型圖文詳解

Java記憶體模型圖文詳解

Nov 30, 2019 pm 04:27 PM
java

Java記憶體模型圖文詳解

1. 概述

#多任務和高並發是衡量一台電腦處理器的能力重要指標之一。一般衡量一個伺服器效能的高低好壞,使用每秒事務處理數(Transactions Per Second,TPS)這個指標比較能說明問題,它代表著一秒內伺服器平均能回應的請求數,而TPS值與程式的並發能力有著非常密切的關係。在討論Java記憶體模型和執行緒之前,先簡單介紹一下硬體的效率與一致性。 (建議:java影片教學

2.硬體的效率與一致性

由於電腦的儲存設備與處理器的運算能力之間有幾個數量級的差距,所以現代電腦系統都必須加入一層讀寫速度盡可能接近處理器運算速度的高速緩存(cache)來作為記憶體與處理器之間的緩衝:將運算需要使用到的資料複製到快取中,讓運算能快速進行,當運算結束後再從快取同步回記憶體之中沒這樣處理器就無需等待緩慢的記憶體讀寫了。

基於高速緩存的儲存互動很好地解決了處理器與記憶體的速度矛盾,但是引入了一個新的問題:快取一致性(Cache Coherence)。在多處理器系統中,每個處理器都有自己的高速緩存,而他們又共享同一主記憶體。

如下圖所示:多個處理器運算任務都涉及同一塊主存,需要一種協定可以保障資料的一致性,這類協定有MSI、MESI、MOSI及Dragon Protocol等。 Java虛擬機器記憶體模型中定義的記憶體存取操作與硬體的快取存取操作是具有可比性的,後續將介紹Java記憶體模型。

Java記憶體模型圖文詳解

除此之外,為了使得處理器內部的運算單元能竟可能被充分利用,處理器可能會對輸入程式碼進行亂起執行(Out-Of -Order Execution)最佳化,處理器會在計算之後將對亂序執行的程式碼進行結果重組,確保結果準確性。與處理器的亂序執行最佳化類似,Java虛擬機器的即時編譯器中也有類似的指令重排序(Instruction Recorder)最佳化。

3.Java記憶體模型

定義Java記憶體模型並不是一件容易的事情,這個模型必須定義得夠嚴謹,才能讓Java的同時操作不會產生歧義;但是,也必須得夠寬鬆,使得虛擬機器的實作能有足夠的自由空間去利用硬體的各種特性(暫存器、快取等)來獲得更好的執行速度。經過長時間的驗證和修補,在JDK1.5發布後,Java記憶體模型就已經成熟和完善起來了。

3.1 主記憶體與工作記憶體

Java記憶體模型的主要目標是定義程式中各個變數的存取規則,即在虛擬機器中將變數儲存到記憶體和從記憶體中取出變數這樣底層細節。此處的變數與Java程式設計時所說的變數不一樣,指包含了實例欄位、靜態欄位和構成陣列物件的元素,但是不包含局部變數與方法參數,後者是執行緒私有的,不會被共用。

Java記憶體模型中規定了所有的變數都儲存在主記憶體中,每個執行緒都有自己的工作記憶體(可以與前面將的處理器的快取類比),在線程的工作記憶體中保存了該執行緒使用到的變數到主記憶體副本拷貝,執行緒對變數的所有操作(讀取、賦值)都必須在工作記憶體中進行,而不能直接讀寫主記憶體中的變數。

不同線程之間無法直接存取對方工作記憶體中的變量,線程間變量值的傳遞均需要在主記憶體來完成,線程、主記憶體和工作記憶體的交互關係如下圖所示,和上圖很類似。

Java記憶體模型圖文詳解

這裡的主記憶體、工作記憶體與Java記憶體區域的Java堆、堆疊、方法區不是相同層次記憶體劃分。

3.2 記憶體間互動操作

關於主記憶體與工作記憶體之間的具體互動協議,即一個變數如何從主記憶體拷貝到工作記憶體、如何從工作記憶體同步到主記憶體之間的實作細節,Java記憶體模型定義了以下八種操作來完成:

1、lock(鎖定):作用於主記憶體的變量,把一個變數標識為一條線程獨佔狀態。

2、unlock(解鎖):作用於主記憶體變量,把一個處於鎖定狀態的變數釋放出來,釋放後的變數才可以被其他執行緒鎖定。

3、read(讀取):作用於主記憶體變量,把一個變數值從主記憶體傳送到執行緒的工作記憶體中,以便隨後的load動作使用

4、load(載入):作用於工作記憶體的變量,它把read操作從主記憶體中得到的變數值放入工作記憶體的變數副本中。

5、use(使用):作用於工作記憶體的變量,把工作記憶體中的一個變數值傳遞給執行引擎,每當虛擬機器遇到一個需要使用變數的值的字節指令時將會執行這個操作。

6、assign(賦值):作用於工作記憶體的變量,它把一個從執行引擎接收到的值賦值給工作記憶體的變量,每當虛擬機器遇到一個給變量賦值的字節碼指令時執行這個操作。

7、store(儲存):作用於工作記憶體的變量,把工作記憶體中的一個變數的值傳送到主記憶體中,以便隨後的write的操作。

8、write(寫入):作用於主記憶體的變量,它把store運算從工作記憶體中一個變數的值傳送到主記憶體的變數。

如果要把一個變數從主內存複製到工作內存,就需要按順尋地執行read和load操作,如果把變數從工作內存中同步回主內存中,就要按順序地執行store和write操作。

Java記憶體模型只要求上述操作必須依序執行,而沒有保證必須是連續執行。也就是read和load之間,store和write之間是可以插入其他指令的,如對主記憶體中的變數a、b進行存取時,可能的順序是read a,read b,load b,load a。 Java記憶體模型也規定了在執行上述八種基本操作時,必須滿足以下規則:

1、不允許read和load、store和write操作之一單獨出現

2、不允許一個線程丟棄它的最近assign的操作,即變數在工作內存中改變了之後必須同步到主內存中。

3、不允許一個執行緒無原因地(沒有發生過任何assign操作)把資料從工作記憶體同步回主記憶體。

4、一個新的變數只能在主記憶體中誕生,不允許在工作記憶體中直接使用一個未被初始化(load或assign)的變數。也就是對一個變數實作use和store操作之前,必須先執行過了assign和load操作。

5、一個變數在同一時刻只允許一條執行緒對其進行lock操作,lock和unlock必須成對出現

6、如果對一個變數執行lock操作,將會清空工作記憶體中此變數的值,在執行引擎使用這個變數前需要重新執行load或assign操作初始化變數的值

7、如果一個變數事先沒有被lock操作鎖定,則不允許對它執行unlock操作;也不允許去unlock一個被其他執行緒鎖定的變數。

8、對一個變數執行unlock操作之前,必須先把此變數同步到主記憶體中(執行store和write操作)。

 3.3 重新排序

在執行程式時為了提高效能,編譯器和處理器經常會對指令進行重新排序。重新排序分成三種:

1、編譯器最佳化的重新排序。編譯器在不改變單執行緒程式語意放入前提下,可以重新安排語句的執行順序。

2、指令級並行的重新排序。現代處理器採用了指令層級並行技術來將多條指令重疊執行。如果不存在資料依賴性,處理器可以改變語句對應機器指令的執行順序。

3、記憶體系統的重新排序。由於處理器使用快取和讀寫緩衝區,這使得載入和儲存操作看起來可能是在亂序執行。

從Java原始碼到最終實際執行的指令序列,會經過下面三種重排序:

Java記憶體模型圖文詳解為了確保記憶體的可見性,Java編譯器在產生指令序列的適當位置會插入記憶體屏障指令來禁止特定類型的處理器重新排序。 Java記憶體模型把記憶體屏障分為LoadLoad、LoadStore、StoreLoad和StoreStore四種:

Java記憶體模型圖文詳解更多java知識請關注java基礎教學欄位。

以上是Java記憶體模型圖文詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

Java程序查找膠囊的體積 Java程序查找膠囊的體積 Feb 07, 2025 am 11:37 AM

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

創造未來:零基礎的 Java 編程 創造未來:零基礎的 Java 編程 Oct 13, 2024 pm 01:32 PM

Java是熱門程式語言,適合初學者和經驗豐富的開發者學習。本教學從基礎概念出發,逐步深入解說進階主題。安裝Java開發工具包後,可透過建立簡單的「Hello,World!」程式來實踐程式設計。理解程式碼後,使用命令提示字元編譯並執行程序,控制台上將輸出「Hello,World!」。學習Java開啟了程式設計之旅,隨著掌握程度加深,可創建更複雜的應用程式。

PHP:許多網站的基礎 PHP:許多網站的基礎 Apr 13, 2025 am 12:07 AM

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

See all articles