1. 程式人生 > >【併發程式設計】一文帶你讀懂深入理解Java記憶體模型(面試必備)

【併發程式設計】一文帶你讀懂深入理解Java記憶體模型(面試必備)

併發程式設計這一塊內容,是高階資深工程師必備知識點,25K起如果不懂併發程式設計,那基本到頂。但是併發程式設計內容龐雜,如何系統學習?本專題將會系統講解併發程式設計的所有知識點,包括但不限於:

執行緒通訊機制,深入JMM記憶體模型原理,深入synchronized原理,深入volatile原理,DCL,詳解AQS,CAS,可重入鎖,讀寫鎖原理,詳解併發工具類,深入理解threadLocal,Fork、Join,原子類詳解,Java併發集合詳解(ConcurrentHashMap,ConcurrentLinedQueue,ConcurrentListMap等),阻塞佇列深入探究,深入執行緒池原理及其設計思想。 本文為深入理解java記憶體模型。

零、全文思維導圖

主線如上圖紅色箭頭,大家可以先看看整體講的是什麼。java記憶體模型前面是鋪墊,後面是相關內容。

一、引出java記憶體模型(不做重點講解)

二、那什麼才會用到java記憶體模型?

共享變數(例項域,靜態域,陣列元素)才會用到。 區域性變數,方法定義引數等不會線上程間共享,所以他們不會有記憶體可見性問題,也不受記憶體模型影響

三、java記憶體模型抽象示意圖

Java記憶體模型簡稱JMM(Java Memory Model),是Java虛擬機器所定義的一種抽象規範,用來遮蔽不同硬體和作業系統的記憶體訪問差異,讓java程式在各種平臺下都能達到一致的記憶體訪問效果。

3.1 主記憶體(Main Memory)

主記憶體可以簡單理解為計算機當中的記憶體,但又不完全等同。主記憶體被所有的執行緒所共享,對於一個共享變數(比如靜態變數,或是堆記憶體中的例項)來說,主記憶體當中儲存了它的“本尊”。

3.2 本地記憶體(Working Memory)

本地記憶體可以簡單理解為計算機當中的CPU快取記憶體,但又不完全等同。每一個執行緒擁有自己的工作記憶體,對於一個共享變數來說,工作記憶體當中儲存了它的“副本”。為啥有本地記憶體這個概念?因為直接操作主記憶體太慢了

通過一系列記憶體讀寫的操作指令(JVM記憶體模型共定義了8種記憶體操作指令,以後會細講),執行緒A把靜態變數 s=0 從主記憶體讀到工作記憶體,再把 s=3 的更新結果同步到主記憶體當中。從單執行緒的角度來看,這個過程沒有任何問題。

四、指令重排序

理解重排序前這個概念前,我們先轉換場景,從java記憶體模型走出來,來到硬體CPU這個維度。

4.1基本概念:

在執行程式時為了提高效能,編譯器和處理器常常會對指令做重排序(簡單理解就是原本我們寫的程式碼指令執行順序應該是A→B→C,但是現在的CPU都是多核CPU,為了秀下優越,為了提高並行度,為了提高效能等,可能會出現指令順序變為B→A→C等其他情況)。

當然CPU們也不是隨便就去重排序,需要滿足以下兩個條件(遵循的規則):

  1. 在單執行緒環境下不能改變程式執行的結果;
  2. 存在資料依賴關係的不允許重排序

4.2重排序分三類:

  1. 編譯器優化的重排序。編譯器在不改變單執行緒程式語義的前提下,可以重新安排語句的執行順序。
  2. 指令級並行的重排序。現代處理器採用了指令級並行技術來將多條指令重疊執行。如果不存在資料依賴性,處理器可以改變語句對應機器指令的執行順序。
  3. 記憶體系統的重排序。由於處理器使用快取和讀/寫緩衝區,這使得載入和儲存操作看上去可能是在亂序執行。

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

那麼重排序會遵循什麼樣的規則?

五、as-if-serial

5.1as-if-serial語義的意思是:

不管怎麼重排序,(單執行緒)程式的執行結果不能被改變。編譯器,runtime和處理器都必須遵守as-if-serial語義。OK,這就相當於給CPU們定下規則。不要隨便重排序。要滿足我這個as-if-serial的前置條件,才能重排序。

5.2

as-if-serial語義把單執行緒程式保護了起來,遵守as-if-serial語義的編譯器,runtime和處理器共同為編寫單執行緒程式的程式設計師建立了一個幻覺:單執行緒程式是按程式的順序來執行的。as-if-serial語義使程式設計師不必擔心單執行緒中重排序的問題干擾他們,也無需擔心記憶體可見性問題。

注意:as-if-serial只保證單執行緒環境,多執行緒環境下無效。那多執行緒,併發程式設計下怎麼辦?

六、多執行緒下導致的問題及解決辦法

上面的這些重排序都可能導致多執行緒程式出現記憶體可見性問題,JMM那麼如何解決?

  • 對於編譯器重排序,JMM 的編譯器重排序規則會禁止特定型別的編譯器重排序(不是所有的編譯器重排序都要禁止)。
  • 對於處理器重排序,JMM 的處理器重排序規則會要求 Java 編譯器在生成指令序列時,插入特定型別的記憶體屏障指令,通過記憶體屏障指令來禁止特定型別的處理器重排序(不是所有的處理器重排序都要禁止)。

JMM屬於語言級的記憶體模型,它確保在不同的編譯器和不同的處理器平臺之上,通過禁止特定型別的編譯器重排序和處理器重排序,為程式設計師提供一致的記憶體可見性保證

七、什麼是記憶體屏障?

7.1 記憶體屏障(Memory Barrier)是一種CPU指令‘。

記憶體屏障也稱為記憶體柵欄或柵欄指令,是一種屏障指令,它使CPU或編譯器對屏障指令之前和之後發出的記憶體操作執行一個排序約束。

7.2 實際運用場景:

volatile便是基於記憶體屏障實現的。 **觀察加入volatile關鍵字和沒有加入volatile關鍵字時所生成的彙編程式碼發現,加入volatile關鍵字時,會多出一個lock字首指令。**這個指令就相當於一個記憶體屏障。具體表現為:

  • 當寫一個volatile 變數時,JMM 會把該執行緒對應的本地記憶體中的共享變數值立即重新整理到主記憶體中。
  • 當讀一個volatile 變數時,JMM 會把該執行緒對應的本地記憶體設定為無效,直接從主記憶體中讀取共享變數

從而保證了,如果某個執行緒對volatile修飾的共享變數進行更新,那麼其他執行緒可以立馬看到這個更新,這就是所謂的執行緒可見性。

(注,關於volatile會在後面單章講解,這裡不過於贅婿)

八、happens-before原則

從jdk5開始,java使用新的JSR-133記憶體模型,基於happens-before的概念來闡述操作之間的記憶體可見性。 換句話說,在JMM中,如果一個操作執行的結果需要對另一個操作可見,那麼這兩個操作之間必須存在happens-before關係。 happens-before原則是JMM中非常重要的原則,它是判斷資料是否存在競爭、執行緒是否安全的主要依據,保證了多執行緒環境下的可見性。 這個的兩個操作既可以在同一個執行緒,也可以在不同的兩個執行緒中。

摘錄一些happens-before規則如下: 1、程式順序規則:一個執行緒中的每個操作,happens-before於該執行緒中任意的後續操作。 2、監視器鎖規則:對一個鎖的解鎖操作,happens-before於隨後對這個鎖的加鎖操作。 3、volatile域規則:對一個volatile域的寫操作,happens-before於任意執行緒後續對這個volatile域的讀。 4、傳遞性規則:如果 A happens-before B,且 B happens-before C,那麼A happens-before C。 注意:兩個操作之間具有happens-before關係,並不意味前一個操作必須要在後一個操作之前執行!僅僅要求前一個操作的執行結果,對於後一個操作是可見的,且前一個操作按順序排在後一個操作之前。

那麼說了那麼多規則,來看看happens-before與JMM的關係

九、as-if-serial和happens-before小結

  • as-if-serial語義保證單執行緒內程式的執行結果不被改變
  • happens-before關係保證正確同步的多執行緒程式的執行結果不被改變。
  • 其實都是為了在不改變程式執行結果的前提下,儘可能地提高程式執行的並行度。

十、扯了那麼久,這幾者如何理解?結論:

  • 重排序是多核CPU等為了效能進行的優化操作,但會導致可見性等問題。為了解決這些問題,所以JMM需要制定一些規則,不讓其隨意重排序。
  • as-if-serial只保證單執行緒環境的不可隨意重排序,那麼多執行緒下呢?
  • 所以有了happens-before原則,其是JMM(JSR-133記憶體模型)的規範之一。
  • 記憶體屏障是CPU指令。
  • 所以說,happens-before是JMM制定的最終目的,記憶體屏障則是實現happens-before的具體手段。

END

彩蛋福利

免費獲取Java學習筆記,面試,文件以及視訊

部分資料如下:

相關推薦

併發程式設計深入理解Java記憶體模型面試必備

併發程式設計這一塊內容,是高階資深工程師必備知識點,25K起如果不懂併發程式設計,那基本到頂。但是併發程式設計內容龐雜,如何系統學

工業大資料《工業大資料白皮書》

來源:工信部、工業網際網路城市物聯網智庫 整理髮布轉載請註明來源和出處------   【導讀】

專案實踐搞定頁面許可權、按鈕許可權以及資料許可權

![許可權授權.png](https://img2020.cnblogs.com/blog/1496775/202101/1496775-20210108142933342-1432167452.jpg) > 以專案驅動學習,以實踐檢驗真知 # 前言 許可權這一概念可以說是隨處可見:等級不夠進入不了某個

專案實踐搞定Spring Security + JWT

![首圖.png](https://img2020.cnblogs.com/news/1496775/202101/1496775-20210112085019858-1640273167.jpg) > 以專案驅動學習,以實踐檢驗真知 # 前言 關於認證和授權,R之前已經寫了兩篇文章: [

從原始碼入手,Spring AOP面向切面程式設計

基於這兩者的實現上,這次來探索下Spring的AOP原理。雖然AOP是基於Spring容器和動態代理,但不瞭解這兩者原理也絲毫不影響理解AOP的原理實現,因為大家起碼都會用。 AOP,Aspect Oriented Programming,面向切面程式設計。在很多

slam是什麼意思?SLAM

  SLAM是Simultaneous localization and mapping縮寫,意為“同步定位與建圖”,主要用於解決機器人在未知環境運動時的定位與地圖構建問題,為了讓大家更多的瞭解SLAM,以下將從SLAM的應用領域、SLAM框架、SLAM分類(基於感測器的SLAM分類)

獨家 | 特徵工程!

作者:Bhalchandra Madhekar 翻譯:陳之炎校對:張玲本文約1800字,建議閱讀

Cascade R-CNN,一個使的檢測更加準確的網路

論文名稱:Cascade R-CNN: Delving into High Quality Object Detection 作者:Zhaowei Cai & Nuno Vasconcelos 論文連結:https://arxiv.org/abs/1712.0072

激光雷達是什麽?激光雷達

很好 高度 組成 b- 距離 style www. 任務 nbsp 隨著人工智能的發展 ,激光雷達也獲得了廣泛的關註,在機器人領域,激光雷達可以幫助機器人在未知環境中了解周邊地圖信息,為後續定位導航提供很好的環境認知能力,幫助機器人實現智能行走。 什麽是激光雷達?

瞭解js資料儲存及深複製深拷貝與淺複製(淺拷貝)

## 背景 在日常開發中,偶爾會遇到需要複製物件的情況,需要進行物件的複製。 由於現在流行標題黨,所以,一文帶你瞭解js資料儲存及深複製(深拷貝)與淺複製(淺拷貝) ## 理解 首先就需要理解 js 中的資料型別了 js 資料型別包含 1. `基礎型別`:`String`、`Number`、 `nul

深入理解Java記憶體模型——基礎

併發程式設計模型的分類 在併發程式設計中,我們需要處理兩個關鍵問題:執行緒之間如何通訊及執行緒之間如何同步(這裡的執行緒是指併發執行的活動實體)。通訊是指執行緒之間以何種機制來交換資訊。在指令式程式設計中,執行緒之間的通訊機制有兩種:共享記憶體和訊息傳遞。 在共享記憶體的併發模型裡,執行緒之

RabbitMQ搞定RabbitMQ死信佇列

本文口味:爆炒魷魚   預計閱讀:15分鐘 一、說明 RabbitMQ是流行的開源訊息佇列系統,使用erlang語言開發,由於其社群活躍度高,維護更新較快,效能穩定,深得很多企業的歡心(當然,也包括我現在所在公司【手動滑稽】)。 為了保證訂單業務的訊息資料不丟失,需要使用到RabbitMQ的死信佇列機制,當訊

RabbitMQ搞定RabbitMQ延遲佇列

本文口味:魚香肉絲   預計閱讀:10分鐘 一、說明 在上一篇中,介紹了RabbitMQ中的死信佇列是什麼,何時使用以及如何使用RabbitMQ的死信佇列。相信通過上一篇的學習,對於死信佇列已經有了更多的瞭解,這一篇的內容也跟死信佇列息息相關,如果你還不瞭解死信佇列,那麼建議你先進行上一篇文章的閱讀。 這一篇

最小生成樹演算法圖解--理解什麼是Prim演算法和Kruskal演算法

假設以下情景,有一塊木板,板上釘上了一些釘子,這些釘子可以由一些細繩連線起來。假設每個釘子可以通過一根或者多根細繩連線起來,那麼一定存在這樣的情況,即用最少的細繩把所有釘子連線起來。 更為實際的情景是這樣的情況,在某地分佈著N個村莊,現在需要在N個村莊之間修路,每個村莊之前的距離不同,問怎麼修最短的路,將各個

快速瞭解最火的數字經濟大資料、人工智慧等都有

人工智慧行業應用加速(暴富機會由“網際網路+”轉向AI+) “網際網路+”紅利已開發將盡,未來,新的暴富紅利將由“人工智慧”接棒。從產業演進看,科技巨頭正加速全球化併購,打造AI生態閉環,開源化也將成為全球性趨勢。開源化使得人工智慧的行業運用門檻急遽降低,未來幾年將迎來人工智慧行業應用浪潮。 2

卷積神經網路(CNN)讓意想不到的10創新idea

    全文摘要 卷積神經網路(CNN)可以說是深度學習發展的一個縮影,特別是現在在計算機視覺方面已經得到了非常成熟的應用,在目標檢測、目標追蹤等方面也是獨領風騷,本文將講述卷積神經網路近些年來的發展歷程,以及它到底創新在什麼地方。本文略長,看完大約3

cookie,面試前端不用愁

本文由雲+社群發表 在前端面試中,有一個必問的問題:請你談談cookie和localStorage有什麼區別啊? localStorage是H5中的一種瀏覽器本地儲存方式,而實際上,cookie本身並不是用來做伺服器儲存的。但在 localStorage 出現之前,cookie被濫用當做了儲存工具,什麼資

Livy——基於Apache Spark的REST服務

背景 Apache Spark作為當前最為流行的開源大資料計算框架,廣泛應用於資料處理和分析應用,它提供了兩種方式來處理資料:一是互動式處理,比如使用者使用spark-shell或是pyspark指令碼啟動Spark應用程式,伴隨應用程式啟動的同時Spark會在當前終端啟動REPL(Read–Eval–Pr

全乾貨 5 分鐘 Docker !

Docker是啥? 開啟翻譯君輸入Docker 結果顯示碼頭工人,沒錯!碼頭工人搬運的是集裝箱,那麼今天要講的Docker其操作的也是集裝箱,這個集裝箱就靜態而言就是一個應用映象檔案,就動態而言,就是一個容器。蒙了吧?好吧,上圖解釋。 Docker從狹義上來講就是一個程序,

和我一起學程式設計系列(1):資料庫聯合查詢(sql joins)的原理,笛卡爾積

格式和我原來的不一致,將就看吧 和我一起學程式設計系列(1):-1.補充,笛卡爾積的概念 首先得有兩個集合, ​ A={1,2},B={3,4}A={1,2},B={3,4} 那麼他們的笛卡爾積就是: 即他們的笛卡爾積CC ​