Java內存模型的深層理論

本文部份內容選自<<深刻理解Java虛擬機>> 以及 CrazyDailyQuestion的ArtarisCNgit

引言

  Java 內存模型 , 即 Java Memory Model,JMM 來屏蔽各類硬件和操做系統的內存訪問差別,以實現讓Java 在各類平臺都達到一致的訪問效果.Java 內存模型規範了 JVM 如何 禁用緩存編譯優化 的方法.github

一.Main Memory和Working Memory

  • Java 規定全部的變量都存儲在主內存(Main Memory)中
  • 每條線程Working Memory 保存了該Thread使用的變量的Main Memory副本copy
    • Thread間變量值經過 Main Memory 傳遞
    • Thread對變量操做(賦值,讀取)只能在 Working Memory 進行, Main Memory 不可讀
    • ThreadA 沒法 直接 訪問 ThreadB Working Memory 變量,同理ThreadB也是如此

下面我就用圖文並茂的方式給你們展現一下: Thread,Main Memory和Working Memory的交互關係緩存

二.內存間交互操做

那麼,變量是如何經過Main Memory copy給 Working Memory,如何從 Work Memory sync 到 Main Memory的呢?安全

jvm實現必須保證每一種操做都是原子的,不可細分的(double 和 long比較特殊)併發

Java 提出了 8種操做類型app

變量做用域: Main Memoryjvm

方法 做用
lock(🔒) 把Thread 設置線程獨有 Tag
unlock(🔓) 釋放變量,給其餘Thread使用
read(讀取) 變量從Main Memory傳輸到Thread 的 Working Memory途徑

變量做用域: Working Memory優化

方法 做用
load(載入) 變量值放到Working Memory 的變量副本中
use(使用) Working Memory的變量值傳給執行引擎,JVM收到須要執行的變量的字節碼指令時候,會執行這個操做
assign(賦值) 他把一個從執行引擎接收的值賦給Working Memory 的變量,JVM收到須要執行的變量的字節碼指令時候,會執行這個操做
store(存儲) 把變量值傳給 Main Memory

變量做用域: Main Memorythis

方法 做用
write(寫入) Working Memory的變量放到Main Memory中

操做規則:操作系統

  太官方,主要是爲了解決Java併發安全,Android用的不太多,只想理清流程,不想看細節~

三.volatile

  沒有被volatile位數據能夠分割爲兩個32位進行操做,volatile和syhnronized功能相似,解決多Thread競爭問題

操做規則:

  • 保證變量對多有Thread的可見性
    • 變量值被修改,Thread能當即感知這個值
    • 在切換線程時候,變量可能被重定義,卻來不及更新建議用 volatile,可是 volatile 並不能完美解決線程安全問題,只能作變量提早預判,此時得采用acomic或者syhnronized等其餘方式

四.long和double

  long 和 double 具備非原子性,不須要用考慮使用volatile修飾

五.原子性,可見性,有序性

  • 原子性: 除了 long 和 double之外的基本數據類型都具備原子性

  • 可見性: 當一個線程修改了這個值,其餘線程可以當即感知,即 Main Memory 傳遞的方式具備可見性

    • volatile 能保證新值能當即同步到 Main Memory,以及每次使用 從 Main Memory 當即 refresh.

    • final 字段在constrctor方法 init 後,constrctor 沒有把 "this" 引用傳遞出去(this 逃逸很是危險),那麼在其餘線程中就能看見 final 字段的值

    • synchronized 變量在同步代碼塊,unlock以後,必須回到 Main Memory,執行完write操做

  • 有序性:

    • 本線程中全部操做都是有序的(Whithin-thread As-if-Serial Semantics)

    • ThreadA watch ThreadB 都是無序的(指令重排,Main Memory與Working Memory 同步 延遲)

      • volatile 禁止指令重排

      • synchronized 一個變量 一個時刻只容許一條線程進行lock

六.happen-before

  • 程序次序規則

      在一個程序裏面,按照程序代碼順序,書寫在前面的操做happen-before發生書寫在後面的操做

  • 管程鎖定規則

      同一把鎖,unlock happen-before lock 操做

  • 線程中斷原則

  Thread.intercupt()方法檢測到是否中斷髮生

  • 傳遞性

  Happens-Before 具備傳遞性,若是 A Happens-Before B,B Happens-Before C,則 A Happens-Before C

  • 對象終結規則

  對象 init happen-before finalize()

七.問題致使緣由

  • 緩存致使的可見性問題
  • 切換線程致使的原子性問題
  • 編譯優化帶來的有序性問題「指令重排」
相關文章
相關標籤/搜索