一文詳解Java內存模型與原子性、可見性、有序性

file

1、Java內存模型

Java Memory Modle,簡稱 JMM,中文名稱 Java內存模型,它是一個抽象的概念,用來描述或者規範訪問內存變量的方式。由於各中計算機的操做系統和硬件不一樣,方式機制也可能不一樣,Java內存模型用於屏蔽(適配)各類差別,以此來達到訪問各個平臺的一致的效果。這也是Java誇平臺的重要緣由之一。java

主內存: Java內存規定了全部變量都存儲在主內存(Main Memory)中,各個線程又有本身的本地內存(工做內存),本地內存保存着主內存中部分變量。具體訪問方式以下:面試

file

  • lock加鎖:爲了保證訪問主內存變量的線程安全性,在訪問前通常會加鎖處理;
  • read讀:從主內存中讀取一個變量到工做內存;
  • load加載:把read讀到的變量加載到工做內存的變量副本中;
  • use使用:此時線程可使用其工做內存中的變量了;
  • assign賦值:將處理後的變量賦值給工做內存中的變量;
  • store存儲:將工做內存中的變量存儲到主內存中,以新建new 一個新變量的方式存儲;
  • write寫:將store存在的新變量的引用賦值給被處理的變量;
  • unload解鎖:全部的工做作完,最後解鎖釋放資源。

2、Java內存模型的三大特性

一、原子性(Atomicity)spring

這裏的原子性如同數據庫事務中是原子性,一個或多個操做要麼全執行成功要麼全執行失敗(全不執行)。數據庫

int a = 1;
a++;
double b = 1.5;

Java內存模型只保證單一的操做具備原子性,好比上面的 int a = 1; 是一個單子的操做,因此具備原子性。設計模式

而 a++ 操做在底層會分爲三個操做:安全

1)、讀取a的值給臨時變量;網絡

2)、臨時變量a的值加1操做;數據結構

3)、將加操做後的值賦值給a。多線程

每一個操做都是原子的,但Java內存模型在多線程下並不能保證多操做具備總體原子性,由於它也不知道這個總體內有多少操做,用戶想要達到多操做具備總體原子性,須要對響應的代碼塊作同步(synchronous)處理,好比使用 有鎖的synchronized 或 無鎖的CAS。框架

二、可見性(Visibility)

這裏的可見性是內存可見性。

file

如上圖,線程1和線程2在未同步的狀況下對共享內存(主內存)中的變量進行訪問,好比兩個線程的操做都是對變量a進行加1操做。

假設線程1首先獲取主內存中變量a的值,隨後線程2又獲取了主內存變量a的值,此時它們工做內存中a的值都是1,它們各自將a的值加1操做,而後assign至工做內存,工做內存中變量a的值都是2,而後兩個線程又將值刷新到主內存,最後的結果是主內存中變量a的值是2。

雖然總體對a的值加1操做作了兩次操做,但因爲線程間的操做是互相隔離的,默認狀況下沒法感知內存變量的值在隨後的變化,也就沒法訪問內存中最新的變量值,這就是內存可行性的問題。

如何解決內存可見性的問題?

  • 對進入臨界區的線程作同步處理(好比 synchronized),同一時刻僅有一個線程可以訪問臨界區的資源;
  • 使用 volatile 關鍵字保證內存可見性,它能保證訪問臨界區資源的全部線程總能看到共享資源的最新值;
  • CAS無鎖化。

三、有序性(Ordering)

線程內的全部操做都是有序的,既程序執行的順序按照代碼的前後順序執行。好比下面的示例:

int a = 1;
int b = 2;
int c = a + b;

線程內程序會先執行 int a = 1; ,而後執行 int b = 2; 最後執行int c = a + b;。

文源網絡,僅供學習之用,若有侵權請聯繫刪除。

我將面試題和答案都整理成了PDF文檔,還有一套學習資料,涵蓋Java虛擬機、spring框架、Java線程、數據結構、設計模式等等,但不只限於此。

關注公衆號【java圈子】獲取資料,還有優質文章每日送達。

file

相關文章
相關標籤/搜索