Java多線程之內存可見性與原子性總結

多線程處理共享變量時候的Java中內存模型
這裏寫圖片描述
Java內存模型規定了所有的變量都是存放在主內存中的,當線程使用變量時候都是把主內存裏面的變量拷貝到了自己的工作空間或者叫做工作內存。

線程的working memory 是cpu的寄存器和高速緩存的抽象描述:現在的計算機,cpu在計算的時候,並不總是從內存讀取數據,它的數據讀取順序優先級是:寄存器-高速緩存-內存。線程耗費的是cpu,線程計算的時候,原始的數據來自內存,在計算過程中,有些數據可能頻繁讀取,這些數據被存儲在寄存器和高速緩存中,當線程計算完後,這些緩存的數據在適當的時候應該寫回內存。


由以上我們就可以看出,在多線程情況下,會產生線程安全的問題!! 如果線程A把數據給修改了,還沒來得及寫回內存,但是此時cpu切換到線程B執行,讀取該數據,那麼讀取到的值爲“舊值”,這就是我們所說的 內存可見性


共享變量實現可見性原理
線程1對共享變量的修改要想被線程2看到,必須經過如下2個步驟:

  1. 把工作內存1中共享變量的值刷新到內存中
  2. 把主內存中最新的共享變量的值刷新到工作內存2中

Java內存間交互操作

JLS定義了線程對主存的操作指令:lock,unlock,read,load,use,assign,store,write。這些行爲是不可分解的原子操作,在使用上相互依賴,read-load從主內存複製變量到當前工作內存,use-assign執行代碼改變共享變量值,store-write用工作內存數據刷新主存相關內容。

  • read(讀取):作用於主內存變量,把一個變量值從主內存傳輸到線程的工作內存中,以便隨後的load動作使用
  • load(載入):作用於工作內存的變量,它把read操作從主內存中得到的變量值放入工作內存的變量副本中。
  • use(使用):作用於工作內存的變量,把工作內存中的一個變量值傳遞給執行引擎,每當虛擬機遇到一個需要使用變量的值的字節碼指令時將會執行這個操作。
  • assign(賦值):作用於工作內存的變量,它把一個從執行引擎接收到的值賦值給工作內存的變量,每當虛擬機遇到一個給變量賦值的字節碼指令時執行這個操作。
  • store(存儲):作用於工作內存的變量,把工作內存中的一個變量的值傳送到主內存中,以便隨後的write的操作。
  • write(寫入):作用於主內存的變量,它把store操作從工作內存中一個變量的值傳送到主內存的變量中。

原子性是指一個原子操作在cpu中不可以暫停然後再調度,既不被中斷操作,要不執行完成,要不就不執行。原子操作保證了原子性問題。

x++(包含三個原子操作)a.將變量x 值取出放在寄存器中 b.將將寄存器中的值+1 c.將寄存器中的值賦值給x

由Java內存模型來直接保證的原子性變量操作包括read、load、use、assign、store和write六個,大致可以認爲基礎數據類型的訪問和讀寫是具備原子性的。如果應用場景需要一個更大範圍的原子性保證,Java內存模型還提供了lock和unlock操作來滿足這種需求,儘管虛擬機未把lock與unlock操作直接開放給用戶使用,但是卻提供了更高層次的字節碼指令monitorenter和monitorexit來隱匿地使用這兩個操作,這兩個字節碼指令反映到Java代碼中就是同步塊—synchronized關鍵字,因此在synchronized塊之間的操作也具備原子性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章