天天看點

Java記憶體模型深入詳解(JMM)(下)3 記憶體間同步操作

3 記憶體間同步操作

3.1 線程操作的定義

操作定義

write要寫的變量以及要寫的值。

read要讀的變量以及可見的寫入值(由此,我們可以确定可見的值)。

lock要鎖定的管程(螢幕monitor)。

unlock要解鎖的管程。

外部操作(socket等等…)

啟動和終止

程式順序

如果一個程式沒有資料競争,那麼程式的所有執行看起來都是順序一緻的

本規範隻涉及線程間的操作;

一個變量如何從主記憶體拷貝到工作記憶體,從工作記憶體同步回主記憶體的實作細節

JMM 本身已經定義實作了以下8種操作來完成,且都具備原子性

lock(鎖定)

作用于主記憶體變量,把一個變量辨別為一條線程獨占的狀态

unlock(解鎖)

作用于主記憶體變量,把一個處于鎖定狀态的變量釋放,釋放後的變量才可以被其它線程鎖定

unlock之前必須将變量值同步回主記憶體

read(讀取)

作用于主記憶體變量,把一個變量的值從主記憶體傳輸到工作記憶體,以便随後的load

load(載入)

作用于工作記憶體變量,把read從主記憶體中得到的變量值放入工作記憶體的變量副本

use(使用)

作用于工作記憶體變量,把工作記憶體中一個變量的值傳遞給執行引擎,每當虛拟機遇到一個需要使用到的變量的值得位元組碼指令時将會執行這個操作

assign(指派)

作用于工作記憶體變量,把一個從執行引擎接收到的值賦給工作記憶體的變量,每當虛拟機遇到一個給變量指派的位元組碼指令時執行這個操作

store(存儲)

作用于工作記憶體變量,把工作記憶體中一個變量的值傳送到主記憶體,以便随後的write操作使用

write(寫入)

作用于主記憶體變量,把store操作從工作記憶體中得到的值放入主記憶體的變量中

把一個變量從主記憶體複制到工作記憶體

就要順序執行read和load

把變量從工作記憶體同步回主記憶體

就要順序地執行store和write操作

JMM隻要求上述兩個操作必須按序執行,而沒有保證連續執行

也就是說read/load之間、store/write之間可以插入其它指令

如對主記憶體中的變量a,b通路時,一種可能出現的順序是read a->readb->loadb->load a

JMM規定執行上述八種基礎操作時必須滿足如下

3.1 同步規則

◆ 對于螢幕 m 的解鎖與所有後續操作對于 m 的加鎖

同步

(之前的操作保持可見)

◆對 volatile變量v的寫入,與所有其他線程後續對v的讀同步

 啟動 線程的操作與線程中的第一個操作同步

◆ 對于每個屬性寫入預設值(0, false, null)與每個線程對其進行的操作同步

◆ 線程 T1的最後操作與線程T2發現線程T1已經結束同步。( isAlive ,join可以判斷線程是否終結)

◆ 如果線程 T1中斷了T2,那麼線程T1的中斷操作與其他所有線程發現T2被中斷了同步通過抛出InterruptedException異常,或者調用Thread.interrupted或Thread.isInterrupted

不允許read/load、store/write操作之一單獨出現

不允許一個變量從主記憶體讀取了但工作記憶體不接收,或從工作記憶體發起回寫但主記憶體不接收

不允許一個線程丢棄它的最近的assign

即變量在工作記憶體中改變(為工作記憶體變量指派)後必須把該變化同步回主記憶體

新變量隻能在主記憶體“誕生”,不允許在工作記憶體直接使用一個未被初始化(load或assign)的變量

換話說就是一個變量在實施use,store之前,必須先執行過assign和load

如果一個變量事先沒有被load鎖定,則不允許對它執行unlock,也不允許去unlock一個被其它線程鎖定的變量

對一個變量執行unloack前,必須把此變量同步回主記憶體中(執行store,write)