帶你瞭解 Java內存模型

Java內存模型的規定:html

一、全部變量存儲在主內存中;java

二、每一個線程都有本身的工做內存,且對變量的操做都是在工做內存中進行;linux

三、不一樣線程之間沒法直接訪問彼此工做內存中的變量,要想訪問只能經過主內存來傳遞。面試

Java的線程、工做內存、主內存關係以下圖所示:併發

具體變量從主內存到工做內存,以及從工做內存轉回主內存的實現細節,由下面八個原子性的操做完成:app

lock:做用於主內存變量,將該變量標識爲一個線程獨佔的狀態線程

unlock:做用於主內存變量,將獨佔狀態釋放htm

read:做用於主內存變量,將值拷貝到工做內存中對象

load:做用於工做內存中的變量,將值放到工做內存中的變量副本中排序

use:做用於工做內存中的變量,將值傳給執行引擎

asign:做用於工做內存中的變量,將執行引擎中的值賦給工做內存中的變量

store:做用於工做內存中的變量,將值傳給主內存

write:做用於主內存中的變量,將工做內存中返回的值放到主內存變量中

同時還對上述八個操做進行了一些細節的要求,好比read/load、store/write必須成對出現,未執行過lock的變量不能執行unlock操做等。

劃重點,此處面試常遇到的問題就是對於volatile關鍵字的解讀。

volatile關鍵字

此關鍵字修飾的變量具備兩種效果:一、保證線程間的可見性;二、阻止指令重排序

對於1的實現,它保證load與use必須相鄰調用,即要use這個變量,一定先執行read/load,這樣每次都能獲取到最新的變量值;它又保證asign與store必須相鄰調用,即在工做內存中將該變量改了以後,一定會先同步到主內存中。這樣,volatile關鍵字實現了可見性。至於阻止指令重排序,仍是移步《深刻理解Java虛擬機》一書吧,貧道水平有限,就不在這裏說了。

從另外一個角度來分析,Java內存模型是圍繞着在併發過程當中如何處理原子性、可見性、有序性來創建的。

原子性:八個原子性操做,以及synchronized(lock/unlock未直接開放給用戶,synchronized經過monitorenter跟monitorexit指令調用的lock/unlock操做)

可見性:volatile、synchronized、final這三個關鍵字均經過不一樣方式實現了可見性

有序性:volatile、synchronized 這兩個關鍵字保證有序性,同時還有先行發生(happens-before)原則來保證隱含的默認有序性

下面說說happens-before先行發生原則,先行發生原則用通俗語言表述就是:若是操做A在操做B以前發生,那麼A產生的影響B一樣能觀測到。那麼問題來了,先行發生原則都有哪些呢?一樣有八條,以下:

程序次序規則:同一個線程中按照代碼的順序依次執行

管程鎖定規則:對於同一個鎖,unlock先行發生於後面的lock,即unlock了纔會lock

volatile變量規則:對一個volatile變量的寫操做先行發生於後面對該變量的讀操做,即寫完了纔會讀

線程啓動規則:一個線程的start()方法先行發生於此線程的任何一個動做

線程終止規則:一個線程的全部動做先行發生於該線程的終止檢測

線程中斷規則:對一個線程interrupt()方法的調用先行發生於線程的中斷檢測Thread.interrpted()

對象終結規則:對象的初始化完成先行發生於finalize()方法

傳遞性:顧名思義,A先行發生於B,B先行發生於C,則A必定先行發生於C

總結

Java內存模型基本就這些內容,若是都掌握了的話,非一線互聯網公司基本都能應對自如了(由於一線互聯網公司貧道本人也沒進去><)。

原文來自:https://www.linuxidc.com/Linux/2019-08/160335.htm

本文地址:https://www.linuxprobe.com/read-java-load.html編輯:九十,審覈員:張文祥

Linux命令大全:https://www.linuxcool.com/

相關文章
相關標籤/搜索