Java內存模型深度解析:總結

處理器內存模型

順序一致性內存模型是一個理論參考模型,JMM和處理器內存模型在設計時通常會把順序一致性內存模型作為參照。JMM和處理器內存模型在設計時會對順序一致性模型做一些放松,因為如果完全按照順序一致性模型來實現處理器和JMM,那么很多的處理器和編譯器優化都要被禁止,這對執行性能將會有很大的影響。

根據對不同類型讀/寫操作組合的執行順序的放松,可以把常見處理器的內存模型劃分為下面幾種類型:

  1. 放松程序中寫-讀操作的順序,由此產生了total store ordering內存模型(簡稱為TSO)。
  2. 在前面1的基礎上,繼續放松程序中寫-寫操作的順序,由此產生了partial store order 內存模型(簡稱為PSO)。
  3. 在前面1和2的基礎上,繼續放松程序中讀-寫和讀-讀操作的順序,由此產生了relaxed memory order內存模型(簡稱為RMO)和PowerPC內存模型。

注意,這里處理器對讀/寫操作的放松,是以兩個操作之間不存在數據依賴性為前提的(因為處理器要遵守as-if-serial語義,處理器不會對存在數據依賴性的兩個內存操作做重排序)。

下面的表格展示了常見處理器內存模型的細節特征:

內存模型名稱 對應的處理器

Store-Load 重排序 Store-Store重排序 Load-Load 和Load-Store重排序 可以更早讀取到其它處理器的寫 可以更早讀取到當前處理器的寫
TSO sparc-TSOX64 Y ? ? ? Y
PSO sparc-PSO Y Y ? ? Y
RMO ia64 Y Y Y ? Y
PowerPC PowerPC Y Y Y Y Y

在這個表格中,我們可以看到所有處理器內存模型都允許寫-讀重排序,原因在第一章以說明過:它們都使用了寫緩存區,寫緩存區可能導致寫-讀操作重排序。同時,我們可以看到這些處理器內存模型都允許更早讀到當前處理器的寫,原因同樣是因為寫緩存區:由于寫緩存區僅對當前處理器可見,這個特性導致當前處理器可以比其他處理器先看到臨時保存在自己的寫緩存區中的寫。

上面表格中的各種處理器內存模型,從上到下,模型由強變弱。越是追求性能的處理器,內存模型設計的會越弱。因為這些處理器希望內存模型對它們的束縛越少越好,這樣它們就可以做盡可能多的優化來提高性能。

由于常見的處理器內存模型比JMM要弱,java編譯器在生成字節碼時,會在執行指令序列的適當位置插入內存屏障來限制處理器的重排序。同時,由于各種處理器內存模型的強弱并不相同,為了在不同的處理器平臺向程序員展示一個一致的內存模型,JMM在不同的處理器中需要插入的內存屏障的數量和種類也不相同。下圖展示了JMM在不同處理器內存模型中需要插入的內存屏障的示意圖:

如上圖所示,JMM屏蔽了不同處理器內存模型的差異,它在不同的處理器平臺之上為java程序員呈現了一個一致的內存模型。

JMM,處理器內存模型與順序一致性內存模型之間的關系

JMM是一個語言級的內存模型,處理器內存模型是硬件級的內存模型,順序一致性內存模型是一個理論參考模型。下面是語言內存模型,處理器內存模型和順序一致性內存模型的強弱對比示意圖:

從上圖我們可以看出:常見的4種處理器內存模型比常用的3中語言內存模型要弱,處理器內存模型和語言內存模型都比順序一致性內存模型要弱。同處理器內存模型一樣,越是追求執行性能的語言,內存模型設計的會越弱。

JMM的設計

從JMM設計者的角度來說,在設計JMM時,需要考慮兩個關鍵因素:

  • 程序員對內存模型的使用。程序員希望內存模型易于理解,易于編程。程序員希望基于一個強內存模型來編寫代碼。
  • 編譯器和處理器對內存模型的實現。編譯器和處理器希望內存模型對它們的束縛越少越好,這樣它們就可以做盡可能多的優化來提高性能。編譯器和處理器希望實現一個弱內存模型。

由于這兩個因素互相矛盾,所以JSR-133專家組在設計JMM時的核心目標就是找到一個好的平衡點:一方面要為程序員提供足夠強的內存可見性保證;另一方面,對編譯器和處理器的限制要盡可能的放松。下面讓我們看看JSR-133是如何實現這一目標的。

為了具體說明,請看前面提到過的計算圓面積的示例代碼:

double pi  = 3.14;    //A
double r   = 1.0;     //B
double area = pi * r * r; //C

上面計算圓的面積的示例代碼存在三個happens- before關系:

  1. A happens- before B;
  2. B happens- before C;
  3. A happens- before C;

由于A happens- before B,happens- before的定義會要求:A操作執行的結果要對B可見,且A操作的執行順序排在B操作之前。 但是從程序語義的角度來說,對A和B做重排序即不會改變程序的執行結果,也還能提高程序的執行性能(允許這種重排序減少了對編譯器和處理器優化的束縛)。也就是說,上面這3個happens- before關系中,雖然2和3是必需要的,但1是不必要的。因此,JMM把happens- before要求禁止的重排序分為了下面兩類:

  • 會改變程序執行結果的重排序。
  • 不會改變程序執行結果的重排序。

JMM對這兩種不同性質的重排序,采取了不同的策略:

  • 對于會改變程序執行結果的重排序,JMM要求編譯器和處理器必須禁止這種重排序。
  • 對于不會改變程序執行結果的重排序,JMM對編譯器和處理器不作要求(JMM允許這種重排序)。

下面是JMM的設計示意圖:

從上圖可以看出兩點:

  • JMM向程序員提供的happens- before規則能滿足程序員的需求。JMM的happens- before規則不但簡單易懂,而且也向程序員提供了足夠強的內存可見性保證(有些內存可見性保證其實并不一定真實存在,比如上面的A happens- before B)。
  • JMM對編譯器和處理器的束縛已經盡可能的少。從上面的分析我們可以看出,JMM其實是在遵循一個基本原則:只要不改變程序的執行結果(指的是單線程程序和正確同步的多線程程序),編譯器和處理器怎么優化都行。比如,如果編譯器經過細致的分析后,認定一個鎖只會被單個線程訪問,那么這個鎖可以被消除。再比如,如果編譯器經過細致的分析后,認定一個volatile變量僅僅只會被單個線程訪問,那么編譯器可以把這個volatile變量當作一個普通變量來對待。這些優化既不會改變程序的執行結果,又能提高程序的執行效率。

JMM的內存可見性保證

Java程序的內存可見性保證按程序類型可以分為下列三類:

  1. 單線程程序。單線程程序不會出現內存可見性問題。編譯器,runtime和處理器會共同確保單線程程序的執行結果與該程序在順序一致性模型中的執行結果相同。
  2. 正確同步的多線程程序。正確同步的多線程程序的執行將具有順序一致性(程序的執行結果與該程序在順序一致性內存模型中的執行結果相同)。這是JMM關注的重點,JMM通過限制編譯器和處理器的重排序來為程序員提供內存可見性保證。
  3. 未同步/未正確同步的多線程程序。JMM為它們提供了最小安全性保障:線程執行時讀取到的值,要么是之前某個線程寫入的值,要么是默認值(0,null,false)。

下圖展示了這三類程序在JMM中與在順序一致性內存模型中的執行結果的異同:

只要多線程程序是正確同步的,JMM保證該程序在任意的處理器平臺上的執行結果,與該程序在順序一致性內存模型中的執行結果一致。

JSR-133對舊內存模型的修補

JSR-133對JDK5之前的舊內存模型的修補主要有兩個:

  • 增強volatile的內存語義。舊內存模型允許volatile變量與普通變量重排序。JSR-133嚴格限制volatile變量與普通變量的重排序,使volatile的寫-讀和鎖的釋放-獲取具有相同的內存語義。
  • 增強final的內存語義。在舊內存模型中,多次讀取同一個final變量的值可能會不相同。為此,JSR-133為final增加了兩個重排序規則。現在,final具有了初始化安全性。

轉載于:https://www.cnblogs.com/dengshiwei/p/4258458.html

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

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

相關文章

sourcetree,創建工作流報錯:Fatal: Not a gitflow-enabled repo yet. Please run 'git flow init' first.-》解決辦法...

1、打開項目下.git/config文件,或者如下圖操作: 2、打開config文件以后,刪除所有 [gitflow *條目并保存文件 3、關閉并重新打開sourcetree 4、倉庫-》Git 工作流-》初始化倉庫即可轉載于:https://www.cnblogs.com/yxfeng/p/10536955.html

關于a標簽的href屬性的注意事項

今天在做一個lightbox效果的時候出現了一個問題。 當往下滾動再點擊按鈕出現lightbox的時候,lightbox的遮罩層不能鋪滿(即滾動高度處不能鋪上),如下圖所示。原因是提交按鈕使用的是a標簽,當給a標簽寫上href屬性的時候&…

爬蟲開發4.三種數據解析方式

數據解析三種方式引言:回顧requests實現數據爬取的流程 指定url基于requests模塊發起請求獲取響應對象中的數據進行持久化存儲其實,在上述流程中還需要較為重要的一步,就是在持久化存儲之前需要進行指定數據解析。因為大多數情況下的需求&…

在mac上安裝gitlab

參考鏈接: https://www.cnblogs.com/floodwater/p/10138265.html 注意事項: 在安裝gitlab-ce時,配置hostname域名后,通過域名訪問gitlab時,需要配置本機hosts文件,不然不能訪問 本地hosts文件中配置后 就可…

org.apache.maven.archiver.MavenArchiver.getManifest錯誤

org.apache.maven.archiver.MavenArchiver.getManifest錯誤 網上普遍要add,,,,, 正解: 接到一個新需求,開始搭建項目時遇到了如標題錯誤。查詢網絡普遍得到是更新maven插件版本。 之前已安裝過此…

d3.js 入門指南

說到數據可視化,我們會行到很多優秀的框架,像echarts、highcharts,這些框架很優雅,健壯,能滿足我們對可視化的大部分需求,但是缺點也很明顯,就是這些框架幾乎是不可定制化的,當遇到特…

【LeetCode】200. 島嶼的個數

題目 給定一個由 1(陸地)和 0(水)組成的的二維網格,計算島嶼的數量。一個島被水包圍,并且它是通過水平方向或垂直方向上相鄰的陸地連接而成的。你可以假設網格的四個邊均被水包圍。 示例 1:輸入: 11110 110…

AI 模擬退火算法

模擬退火算法轉載于:https://www.cnblogs.com/yangwenhuan/p/10548171.html

keep用法

keep 是英語中用法靈活的動詞之一,下面筆者就其用法歸納如下: 一、用作系動詞,意為“保持(某種狀態)”,其后常接形容詞作表語。如: Please keep quiet / silent! 請保持安靜! Aft…

Kubernetes系列之Helm介紹篇

本次系列使用的所需部署包版本都使用的目前最新的或最新穩定版,安裝包地址請到公眾號內回復【K8s實戰】獲取 介紹 Helm 是 Deis 開發的一個用于 Kubernetes 應用的包管理工具,主要用來管理 Charts。有點類似于 Ubuntu 中的 APT 或 CentOS 中的 YUM。Helm…

HTNL筆記整合

簡述概括了HTML 的部分內容,不是很完善,希望能給予你們相對的幫助。 一下文件的整合百度云鏈接:HTML整合筆記 第一章 HTML入門 課時1:HTML初識 1、英文名(Hyper Text Markup Language)超文本標簽語言 對…

EXCEL 圖表 只在拐點的時候顯示數字

EXCEL圖表只在折線的拐點顯示數值,中間不需要顯示。同時往下拐的,顯示在上方,往上的顯示在下方,這樣數值不會擋住線。 首先,做一些模擬數據 因為起點和終點數值必須顯示,所以單元格,C2 D2 C19 D…

淺談Vue之雙向綁定

VUE實現雙向數據綁定的原理就是利用了 Object.defineProperty() 這個方法重新定義了對象獲取屬性值(get)和設置屬性值(set)的操作來實現的。那么Object.defineProperty究竟是該如何使用的呢&#xff1f;先看個例子 <!DOCTYPE html> <html lang"en"><h…

【AtCoder】AGC017

A - Biscuits dp[i][0/1]表示當前和是偶數還是奇數&#xff0c;直接轉移即可 #include <bits/stdc.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define space putchar( ) #define enter putchar…

SQL語法(1、安裝操作)

1、數據庫的系統概述及安裝與基本使用 bilibili可查找安裝視頻百度了解一下 – 使用超級管理員登錄 CONN sys/change_on_install AS SYSDBA ; – 創建c##scott用戶 CREATE USER c##scott IDENTIFIED BY tiger ; – 為用戶授權 GRANT CONNECT,RESOURCE,UNLIMITED TABLESPACE…

java 中文字符和unicode編碼值相互轉化

java 中文字符和unicode編碼值相互轉化 https://blog.csdn.net/u011366045/article/details/79235217 版權聲明&#xff1a;本文為博主原創文章&#xff0c;未經博主允許不得轉載。 https://blog.csdn.net/u011366045/article/details/792352171、引用工具 import com.alibaba.…

Object 及toString() 方法的重寫

Object: 是所有的類的父類 &#xff0c;Object中所有的方法 &#xff0c; 子類都能使用 &#xff0c; 接口不是Object子類。 Person: /*將父類的equals方法 重寫* 不改變父類的源代碼 equals 比較內存地址* 比較兩個成員變量 變量值相等 返回true 不等 返回false* 重…

SQL語法練習

SQL語法練習https://blog.csdn.net/qq_30764991/article/details/81952197員工表建表語句: CREATE TABLE EMP ( ENAME VARCHAR2(30), EMPNO NUMBER(5), DEPTNO NUMBER(5), JOB VARCHAR2(20), HIREDATE DATE, COMM NUMBER(6,2), SAL NUMBER(6,2) ); 部門表建表語句: CREATE TA…

第22章:MongoDB-聚合操作--聚合管道--$out

①$out$out&#xff1a;利用此操作可以將查詢結果輸出到指定的集合里面。②范例&#xff1a;將投影的結果輸出到集合里③④⑤⑥⑦⑧⑨⑩??????????轉載于:https://www.cnblogs.com/Lucky-stars/p/10555296.html

SQL簡單查詢

1、簡單查詢 使用Oracle sql developer使用前&#xff0c;必須開啟的服務&#xff1a; 查詢emp表上的數據&#xff1a; select * from emp; Null為空&#xff0c;空不代表等于沒有&#xff0c;null&#xff01;0. 重新連接后&#xff0c;注意大小寫及空格位&#xff01; 簡…