Java內存模型

計算機結構簡介

  • 五大組成部分:控制器(Control)、運算器(Datapath)、存儲器(Memory)、輸入(Input System)、輸出(Output System)。
    在這裏插入圖片描述

CPU

  • CPU = 控制器 + 運算器
  • 中央處理器,是計算機的控制和運算的核心,程序最終都會變成指令讓CPI去執行,處理程序中的數據

內存

  • 存儲器 = 內存 + 硬盤
  • 程序都是在內存中運行的,內存會保存程序運行時的數據,供CPU處理。

緩存

  • CPU的運算速度和內存訪問速度差距較打,這導致CPU每次操作內存都要耗費很多等待的時間,內存的讀寫速度成爲了計算機運行的瓶頸,於是就有了在CPU和主內存之間增加緩存的設計,最靠近CPU的緩存稱爲L1,然後依次是L2、L3和主內存。
  • CPU Cache分成了三個級別:L1、L2、L3,級別越小越接近CPU,速度也更快,同時也代表容量越小
  • 每個CPU核上都有一個L1 、L2 Cache,在同一個CPU插槽之間的核共享一個L3 Cache。
    在這裏插入圖片描述

Java內存模型

  • Java內存模型(Java Memory Molde, JMM),不要核java內存結構混淆。
  • java內存模型是一套在多線程讀寫共享數據時,對共享數據的可見性、有序性和原子性的規則和保障。
  • Java內存模型是一種規範,描述了Java程序中各種變量(線程共享變量)的訪問規則,以及在JVM中將變量存儲到內存和從內存中讀取變量的底層細節。
  • 主內存:是所有線程共享的,都能訪問,雖有變量都存儲在主內存中。
  • 工作內存:每個線程都有自己的工作內存,工作內存只存儲該線程對共享變量的副本、線程對變量的所有操作(讀、取)都必須在工作內存中進行。不同的線程不能訪問其他線程的工作內存中的變量。
    在這裏插入圖片描述

CPU緩存,內存,Java內存模型的關係

Java內存模型中的工作內存和主內存既可能對應計算機硬件CPU寄存器、也可能時CPU緩存,還有可能時內存,是一種抽象概念劃分餘真實物理硬件的交叉
在這裏插入圖片描述

主內存和工作內存數據交互的過程

Java內存中線程的主內存和工作內存的交互是由Java虛擬機定義瞭如下的8種操作來完成的

  • lock(鎖定):作用於主內存的變量,一個變量在同一時間只能一個線程鎖定,該操作表示這條線成獨佔這個變量

  • unlock(解鎖):作用於主內存的變量,表示這個變量的狀態由處於鎖定狀態被釋放,這樣其他線程才能對該變量進行鎖定

  • read(讀取):作用於主內存變量,表示把一個主內存變量的值傳輸到線程的工作內存,以便隨後的load操作使用

  • load(載入):作用於線程的工作內存的變量,表示把read操作從主內存中讀取的變量的值放到工作內存的變量副本中(副本是相對於主內存的變量而言的)

  • use(使用):作用於線程的工作內存中的變量,表示把工作內存中的一個變量的值傳遞給執行引擎,每當虛擬機遇到一個需要使用變量的值的字節碼指令時就會執行該操作

  • assign(賦值):作用於線程的工作內存的變量,表示把執行引擎返回的結果賦值給工作內存中的變量,每當虛擬機遇到一個給變量賦值的字節碼指令時就會執行該操作

  • store(存儲):作用於線程的工作內存中的變量,把工作內存中的一個變量的值傳遞給主內存,以便隨後的write操作使用

  • write(寫入):作用於主內存的變量,把store操作從工作內存中得到的變量的值放入主內存的變量中
    在這裏插入圖片描述
    Java內存模型還規定了在執行上述八種基本操作時,必須滿足如下規則:

  • 如果要把一個變量從主內存中複製到工作內存,就需要按順尋地執行read和load操作, 如果把變量從工作內存中同步回主內存中,就要按順序地執行store和write操作。但Java內存模型只要求上述操作必須按順序執行,而沒有保證必須是連續執行。

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

  • 不允許一個線程丟棄它的最近assign的操作,即變量在工作內存中改變了之後必須同步到主內存中。

  • 不允許一個線程無原因地(沒有發生過任何assign操作)把數據從工作內存同步回主內存中。

  • 一個新的變量只能在主內存中誕生,不允許在工作內存中直接使用一個未被初始化(load或assign)的變量。即就是對一個變量實施use和store操作之前,必須先執行過了assign和load操作。

  • 一個變量在同一時刻只允許一條線程對其進行lock操作,但lock操作可以被同一條線程重複執行多次,多次執行lock後,只有執行相同次數的unlock操作,變量纔會被解鎖。lock和unlock必須成對出現。

  • 如果對一個變量執行lock操作,將會清空工作內存中此變量的值,在執行引擎使用這個變量前需要重新執行load或assign操作初始化變量的值

  • 如果一個變量事先沒有被lock操作鎖定,則不允許對它執行unlock操作;也不允許去unlock一個被其他線程鎖定的變量。

  • 對一個變量執行unlock操作之前,必須先把此變量同步到主內存中(執行store和write操作)。