標籤:值傳遞 釋放 引擎 其他 str 實現 排序 可見 類型
主記憶體和工作記憶體
工作規則
Java記憶體模型, 定義變數的訪問規則, 即將共用變數儲存到記憶體和取出記憶體的底層細節
所有的變數都儲存在主記憶體中,每條線程有自己的工作記憶體,工作記憶體中用到的變數, 是從主記憶體拷貝的副本,線程對變數的所有操作都在工作記憶體中進行, 線程間變數值得傳遞均需通過主記憶體來完成
記憶體間互動操作
1、luck(鎖定):作用於主記憶體的變數,它把一個變數標示為一條線程獨佔的狀態。2、unlock(解鎖):作用於主記憶體的變數,它把一個處於鎖定狀態的變數釋放出來,釋放後的變數才可以被其他線程鎖定。3、read(讀取):作用於主記憶體的變數,它把一個變數的值從主記憶體傳輸到工作記憶體中,以便隨後的load動作使用。4、load(載入):作用於工作記憶體的變數,它把read操作從主記憶體中得到的變數值放入工作記憶體的變數副本中。5、use(使用):作用於工作記憶體的變數,它把工作記憶體中的一個變數的值傳遞給執行引擎,每當虛擬機器遇到一個需要使用到變數的值得位元組碼指令時將會執行這個操作。6、assign(賦值):作用於工作記憶體的變數,它把一個從執行引擎接收到的值賦給工作記憶體的變數,每當虛擬機器遇到一個給變數賦值的位元組碼指令時執行這個操作。7、store(儲存):作用於工作記憶體的變數,它把工作記憶體中的一個變數的值傳遞到主記憶體中,以便隨後的write操作使用。8、write(寫入):作用於主記憶體的變數,它把store操作從工作記憶體中得到的變數值放入主記憶體的變數中。
上述操作,必須滿足以下的規則:
1、不允許read和load、store和write操作之一單獨出現,以上兩個操作必須按順序執行,但沒有保證必須連續執行,也就是說,read與load之間、store與write之間是可插入其他 指令的。 2、不允許一個線程丟棄它的最近的assign操作,即變數在工作記憶體中改變了之後必須把該變化同步回主記憶體。 3、不允許一個線程無原因地(沒有發生過任何assign操作)把資料從線程的工作記憶體同步回主記憶體中。 4、一個新的變數只能從主記憶體中“誕生”,不允許在工作記憶體中直接使用一個未被初始化(load或assign)的變數,換句話說就是對一個變數實施use和store操作之前,必須先執行過 了assign和load操作。 5、一個變數在同一個時刻只允許一條線程對其執行lock操作,但lock操作可以被同一個條線程重複執行多次,多次執行lock後,只有執行相同次數的unlock操作,變數才會被解鎖。 6、如果對一個變數執行lock操作,將會清空工作記憶體中此變數的值,在執行引擎使用這個變數前,需要重新執行load或assign操作初始設定變數的值。 7、如果一個變數實現沒有被lock伺服器用戶端檔案鎖,則不允許對它執行unlock操作,也不允許去unlock一個被其他線程鎖定的變數。 8、對一個變數執行unlock操作之前,必須先把此變數同步回主記憶體(執行store和write操作)。
happen-before
共用資料的讀寫操作, 如果不滿足happen-bifore條件, 就沒有順序性的保障, 虛擬機器可以對他們進行重排序
重排序
也就是說只要程式的最終結果等同於它在嚴格的順序化環境下的結果,那麼指令的執行順序就可能與代碼的順序不一致,這個過程通過叫做指令的重排序
指令重排序存在的意義在於:JVM能夠根據處理器的特性(CPU的多級緩衝系統、多核處理器等)適當的重新排序機器指令,使機器指令更符合CPU的執行特點,最大限度的發揮機器的效能
特殊的記憶體操作
volatile修飾的變數: 可見度; 禁止指令重排序最佳化
final域 : 被final修飾的欄位在構造器中一旦被初始化完成,在其他線程中就能看到final欄位的值
long和double型變數的特殊規則 : 除了long和double類型, 其他的基本類型和參考型別的賦值操作都為原子操作
Java並發編程--7.Java記憶體操作總結