1. 程式人生 > >附1 Java記憶體模型與共享變數可見性

附1 Java記憶體模型與共享變數可見性

注:本文主要參考自《深入理解Java虛擬機器(第二版)》和《深入理解Java記憶體模型》

1、Java記憶體模型(JMM)

Java記憶體模型的主要目標:定義在虛擬機器中將變數儲存到記憶體和從記憶體中取出變數這樣的底層細節。

注意:上邊的變數指的是共享變數(例項欄位、靜態欄位、陣列物件元素),不包括執行緒私有變數(區域性變數、方法引數),因為私有變數不會存在競爭關係。

1.1、記憶體模型就是一張圖:

說明:

  • 所有共享變數存於主記憶體
  • 每一條執行緒都有自己的工作記憶體(就是上圖所說的本地記憶體)
  • 工作記憶體中儲存了被該執行緒使用到的變數的主記憶體副本

注意:

  • 執行緒對變數的操作都要在工作記憶體中進行,不能直接操作主記憶體
  • 不同的執行緒之間無法直接訪問對方的工作記憶體中的變數
  • 不同執行緒之間的變數的傳遞必須通過主記憶體

類比:(注意:主記憶體與工作記憶體只是一個概念,與堆疊記憶體沒有關係,下邊的類比只是幫助理解)

  • 主記憶體:對應於Java堆中的物件例項資料部分(注意:堆中還儲存了物件的其他資訊,eg.Mark Word、Klass Point和用於位元組對其補白的填充資料)
  • 工作記憶體:對應於棧中的部分割槽域

1.2、8條記憶體屏障指令:

下面只列出6條與之後內容相關的,其餘的檢視《深入理解Java虛擬機器》

  • lock:作用於主記憶體,把一個變數標識為一條執行緒獨佔的狀態
  • unlock:作用於主記憶體
    ,把一個處於鎖定的變數解鎖

下邊四條是與volatile實現記憶體可見性直接相關的四條(store、write、read、load)

  • store:把工作記憶體中的變數的值傳送到主記憶體中
  • write:把store操作從工作記憶體中得到的變數值放入到主記憶體的變數中
  • read:把一個變數的值從主記憶體中傳輸到執行緒的工作記憶體
  • load:把read操作從主記憶體中獲取到的變數值放入工作記憶體的變數中去

注意:

  • 一個變數在同一時刻只允許一條執行緒對其進行lock操作
  • lock操作會將該變數在所有執行緒工作記憶體中的變數副本清空,否則就起不到鎖的作用了
  • lock操作可被同一條執行緒多次進行,lock幾次,就要unlock幾次(可重入鎖)
  • unlock之前必須先執行store-write
  • store-write必須成對出現(工作記憶體-->主記憶體)
  • read-load必須成對出現(主記憶體-->工作記憶體)

2、變數對所有執行緒的可見性

可見性:執行緒1對共享變數的修改能及時被執行緒2看到

2.1、共享變數不可見的原因

  • 共享變數更新後的值沒有在工作記憶體和主記憶體之間及時更新
  • 執行緒交錯執行
  • 指令重排序結合執行緒交錯執行

2.2、實現共享變數及時更新的措施

執行緒1修改過共享變數後,將共享變數刷到主記憶體,然後,執行緒2從主記憶體讀取該共享變數,將該共享變數載入到工作記憶體中

注意:在短時間內的高併發情況下,如果發生下列三種情況,則執行緒2就讀不到執行緒1修改過的最新的值了,

  • 可能執行緒1根本來不及將修改過後的共享變數刷到主記憶體(這個時間非常短,但是還是有)的時候,執行緒2就已經讀取了原有的主記憶體變數到其工作記憶體中。
  • 可能執行緒1雖然將修改過後的值刷到了主記憶體中,但是執行緒2的工作記憶體中的變數副本還沒來得及從CPU重新整理回來,所以執行緒2讀取到的還是原來的工作記憶體中的變數副本
  • 可能執行緒1根本來不及將修改過後的共享變數刷到主記憶體的時候,同時,執行緒2的工作記憶體中的變數副本還沒來得及從CPU重新整理回來

注意:工作記憶體中的變數副本在使用之後,不會立刻消失掉,會一直存在,這樣其值也一直不變,直到對其進行寫操作或資料從CPU中重新整理回來(類比volatile-read的作用)。

2.3、指令重排序:程式碼書寫順序與實際執行順序不同(編譯器或處理器為提高程式效能做的優化)

eg.

書寫程式碼的順序如下:

1         int a = 12;
2         int b = 13;
3         int c = a+b;
View Code

可能實際執行程式碼的順序如下:

1         int b = 13;
2         int a = 12;
3         int c = a+b;
View Code

總結:本文大概介紹了一下Java記憶體模型以及與共享變數可見性的一些概念,為下邊的volatile做準備。

相關推薦

1 Java記憶體模型共享變數可見

注:本文主要參考自《深入理解Java虛擬機器(第二版)》和《深入理解Java記憶體模型》 1、Java記憶體模型(JMM) Java記憶體模型的主要目標:定義在虛擬機器中將變數儲存到記憶體和從記憶體中取出變數這樣的底層細節。 注意:上邊的變數指的是共享變數(例項欄位、靜態欄位、陣列物件元素),不包括執行

Java併發基礎】Java記憶體模型解決有序性和可見

前言 解決併發程式設計中的可見性和有序性問題最直接的方法就是禁用CPU快取和編譯器的優化。但是,禁用這兩者又會影響程式效能。於是我們要做的是按需禁用CPU快取和編譯器的優化。 如何按需禁用CPU快取和編譯器的優化就需要提到Java記憶體模型。Java記憶體模型是一個複雜的規範。其中最為重要的便是Happens

1.java一切即物件以及java記憶體模型執行緒

由此可以得知: 程式碼完成之後進行本地配置的一些讀取操作: 至此可以得知其編譯模式是mixed模式的 new date()預設輸出的結果是import中包的預設建構函式初始化後的結果: 觀看Date類原始碼即可得知: 鑑於java是單繼承關係,由此來看一下imp

java記憶體模型執行緒(1

一、處理器、快取記憶體、主記憶體之前的互動圖 二、Java記憶體模型 倆張圖之間的關係很清晰 一個處理器對應一個執行緒 一個快取記憶體對應一個工作記憶體 問題的關鍵點就在於:java執行緒之間與工作記憶體打交道,而不是主記憶體,工作記憶體之間沒有直接的關

多執行緒讀書筆記二(java記憶體模型、volatile變數記憶體模型synchronized、CAS)

java記憶體模型 java中,執行緒之間的通訊是通過共享記憶體的方式,儲存在堆中的例項域,靜態域以及陣列元素都可以線上程間通訊。java記憶體模型控制一個執行緒對共享變數的改變何時對另一個執行緒可見。 執行緒間的共享變數存在主記憶體中,而對於每一個執行緒,都有一個私有的工

十一、JVM(HotSpot)Java記憶體模型執行緒

注:本博文主要是基於JDK1.7會適當加入1.8內容。 1、Java記憶體模型 記憶體模型:在特定的操作協議下,對特定的記憶體或快取記憶體進行讀寫訪問的抽象過程。不同的物理機擁有不一樣的記憶體模型,而Java虛擬機器也擁有自己的記憶體模型。 主要目標:定義程式中各個變數的訪問規則,

Java記憶體模型執行緒知識點總結

首先討論一下物理機對於併發的處理方案 運算任務不可能只靠處理器簡單的計算就能完成,必須還要增加與記憶體的互動操作(如讀取資料,儲存資料), 由於計算機的儲存裝置與處理器的運算速度之間有著幾個數量級的差距,所以現代計算機系統選擇加入快取記憶體(Cache)來進行記憶體與處理器之間的快取來提高效率 由於快取記

Java記憶體模型執行緒——Java記憶體模型

文章目錄 一、主記憶體與工作記憶體 1.1 Java記憶體模型中的變數 1.2 主記憶體與工作記憶體 二、主記憶體與工作記憶體間互動操作 三、對於volatile型變數的特殊規則 3.1 可見性 3.2

Java記憶體模型執行緒——硬體的效率一致性,記憶體模型

文章目錄 一、先來一個問題,想要電腦快,買記憶體條還是固態硬碟? 二、衡量一個服務效能好壞的標準之一 三、硬體的效率與一致性 3.1 硬體的效率與一致性問題是怎樣出來的? 四、記憶體模型 一、先來一個問題

深入理解Java虛擬機器筆記——Java記憶體模型併發程式設計

  當程式在執行過程中,會將運算需要的資料從主存複製一份到CPU的快取記憶體中,那麼CPU進行計算時就可以直接從它的快取記憶體讀取資料和向其中寫入資料,當運算結束後,再將告訴快取中的資料重新整理到主存中。   如果一個變數在多個CPU中都存在快取,那麼就存在快取一致性

Java記憶體模型執行緒 深入理解Java虛擬機器總結

在許多情況下,讓計算機同時去做幾件事情,不僅是因為計算機的運算能力強大了,還有一個很重要的原因是計算機的運算速度與它的儲存和通訊子系統速度的差距太大, 大量的時間都花費在磁碟I/O、網路通訊或者資料庫訪問上。 如果不希望處理器在大部分時間裡都處於等待其他資源的狀態,就必須使用一些手段去把處理器

讀書筆記 ---- 《深入理解Java虛擬機器》---- 第11篇:Java記憶體模型執行緒

上一篇:晚期(執行期)優化:https://blog.csdn.net/pcwl1206/article/details/84642835 目  錄: 1  概述 2  Java記憶體模型 2.1  主記憶體與工作記憶體 2.2 

Java虛擬機器】Java記憶體模型執行緒

Java記憶體模型與執行緒 Java記憶體模型 記憶體間互動操作 volatile關鍵字 Java與執行緒 核心實現 使用使用者執行緒實現 使用使用者執行緒加輕量級程序混合實現 Java執行緒的實現

深入理解JVM(十一)——Java記憶體模型執行緒

計算機運算的速度,與它的儲存和通訊子系統相差太大,大量的時間花費在磁碟IO,網路通訊和資料庫上。 衡量一個服務效能的高低好壞,每秒事務處理數TPS是最重要的指標。 對於計算量相同的任務,程式執行緒併發協調的越有條不紊,效率越高;反之,執行緒之間頻繁阻塞或是死鎖,將大大降低併發能力。

深入理解 Java 虛擬機器(十二)Java 記憶體模型執行緒

執行緒安全 Java 語言中的執行緒安全 根據執行緒安全的強度排序,Java 語言中各種操作共享的資料可以分為 5 類:不可變、絕對執行緒安全、相對執行緒安全、執行緒相容、執行緒對立。 不可變 不可變的物件一定是執行緒安全的,如果共享資料是一個基本資料型別,那麼

深入理解Java虛擬機器讀書筆記1----Java記憶體區域HotSpot虛擬機器物件

一 Java記憶體區域與HotSpot虛擬機器物件 1 Java技術體系、JDK、JRE?     Java技術體系包括:         · Java程式設計語言;   

java記憶體模型執行緒(2)

一、原子性、可見性與有序性 1.原子性 原子性操作包括read、load、asign、use、store和write 更大範圍的原子性保證:lock和unlock(倆者未開放),monitorenter和monitorexit(隱式的使用synchronized)

Java記憶體模型物件揭祕

看了很多個關於Java記憶體模型的部落格,這篇部落格有著獨到的見解. 前言:最近看了《深入jvm》一書,感受頗深,但是不寫點什麼總感覺不是自己的,所以動手捋一捋。主要講的內容是java的記憶體區域,物件的建立,物件的記憶體佈局和物件的訪問方式。 一、java的記憶體區域劃

深入理解Java虛擬機器讀書筆記8----Java記憶體模型執行緒

八 Java記憶體模型與執行緒   1 Java記憶體模型     ---主要目標:定義程式中各個變數的訪問規則,即在虛擬機器中將變數儲存到記憶體和從記憶體中取出變數這樣的底層細節。     ---此處的變數和Java中的變

jdk原始碼解析(十一)——Java記憶體模型執行緒

前面我們瞭解了Java的編譯和執行,這裡在講解一下高效併發(Java記憶體模型與執行緒)在瞭解記憶體模型與執行緒之前,我們先要了解一些東西。 1 硬體效率與一致性  計算併發執行的執行和充分利用計算機處理器的效能兩者看來是互為因果的,而在大多數的時候,計算機的處理速度不止是在處理器