Java記憶體模型用來屏蔽各種硬體和作業系統的記憶體通路差異,以實作在各種平台下都能達到一緻的并發效果。
主記憶體與工作記憶體
Java記憶體模型的主要目标是/定義程式中各個變量的/通路規則,即在虛拟機中/将變量存儲到記憶體和從記憶體中取出變量這樣的底層細節。
Java記憶體模型規定:
所有的變量都存儲在主記憶體中;
每個線程有自己的工作記憶體,線程的工作記憶體儲存被線程使用到變量的主記憶體副本拷貝;
線程對變量的所有操作都必須在工作記憶體中進行,而不能直接讀寫主記憶體的變量;
不同線程之間不能直接通路對方工作記憶體中的變量,線程間變量值的傳遞通過主記憶體來完成。
<a target="_blank" href="http://blog.51cto.com/attachment/201306/223143376.png"></a>
記憶體間互動操作
Java記憶體模型定義了八種操作:
lock(鎖定):作用于主記憶體的變量,它把一個變量辨別為一個線程獨占的狀态;
unlock(解鎖):作用于主記憶體的變量,它把一個處于鎖定狀态的變量釋放出來,釋放後的變量才可以被其他線程鎖定;
read(讀取):作用于主記憶體的變量,它把一個變量的值從主記憶體傳送到線程中的工作記憶體,以便随後的load動作使用;
load(載入):作用于工作記憶體的變量,它把read操作從主記憶體中得到的變量值放入工作記憶體的變量副本中;
use(使用):作用于工作記憶體的變量,它把工作記憶體中一個變量的值傳遞給執行引擎;
assign(指派):作用于工作記憶體的變量,它把一個從執行引擎接收到的值指派給工作記憶體中的變量;
store(存儲):作用于工作記憶體的變量,它把工作記憶體中的一個變量的值傳送到主記憶體中,以便随後的write操作;
write(寫入):作用于主記憶體的變量,它把store操作從工作記憶體中得到的變量的值寫入主記憶體的變量中。
操作時規則
不允許read和load、store和write操作之一單獨出現;
說明:如果要把一個變量從主記憶體複制到工作記憶體,那要順序執行read和load操作;如果要把變量從工作記憶體同步回主記憶體,就要順序執行store和write操作。Java記憶體模型要求上述連個操作必須按順序執行,但不必須連續執行。
不允許一個線程丢棄它的最近的assign操作,變量在工作記憶體中改變了之後必須把變化同步回主記憶體;
不允許一個線程無原因地把資料從線程的工作記憶體同步回主記憶體;
一個新變量之能在主記憶體誕生,不允許在工作記憶體直接使用一個為被初始化(load或assign)的變量,即在對一個變量實施use和store操作之前,必須先執行assign和load操作;
一個變量在同一個時刻隻允許一條線程對其進行lock操作,但lock操作可以被同一線程重複執行多次,多次執行lock後,隻有執行相同次數的unlock操作,變量才被解鎖;
如果對一個變量執行lock操作,将會清空工作記憶體中此變量的值,在執行引擎使用這個變量前,需要重新執行load或assign操作初始化變量的值;
如果一個變量事先沒有被lock操作鎖定,則不允許對他執行unlock操作;也不允許去unlock一個被其他線程鎖定住的變量;
對一個變量執行unlock操作之前,必須先把此變量同步回主記憶體。
volatile
關鍵字volatile是JVM提供最輕量級的同步機制。
當一個變量被定義成volatile後,它具有兩個特性:
第一,volatile變量對所有線程是立即可見的,對于volatile變量所有的寫操作都能立刻反應到其他線程之中;但volatile變量隻能保證可見性,不能保證在并發下是安全的。
第二,禁止指令重排序優化。
Java模型特性
原子性:J read、load、assign、use、store和write保證原子性變量操作;lock和unlock通過synchronized文法來加鎖,在synchronized塊之間的操作也具有原子性;
可見性:volatile、synchronized和final實作變量修改值在其他線程可見;synchronized可見性是由“對一個變量執行unlock操作之前,必須先把此變量同步回主記憶體中“這條規則獲得的;final可見性是”被final修飾的字段在構造器中一旦被初始化完成,并且構造器沒有把this的引用傳遞出去,那麼在其他線程就能看到final字段的值。“
有序性:Java語言提供volatiel和synchronized兩個關鍵字來保證線程之間的有序性;volatile本身禁止指令重排序;synchronized是由“一個變量在同一個時刻隻允許一條線程對其進行lock操作“這條規則獲得的。
線程是比程序更輕量級的排程執行機關,線程可以把一個程序的資源配置設定和執行排程分開,各個線程既可以共享進度資源,由可以獨立排程。
Java線程實作
Java在Windows與Linux上都是使用一對一的縣城模型來實作,一個Java線程就映射到一條輕量級程序之中。
Java線程排程
線程排程指系統為線程配置設定處理器使用權的過程,主要排程方式分為:協同式和搶占式。Java使用的線程排程方式是搶占式排程。
協同式,線程的執行時間由線程本身來控制,線程執行完之後主動通知系統切換到另一個線程,它的壞處是線程執行時間不可控制。如果一個線程遲遲不讓出CPU執行時間會導緻整個系統崩潰。
搶占式,每個線程由系統來配置設定執行時間,線程的切換由作業系統決定。
狀态裝換
Java定義了5種線程狀态,在任意一個時間點,一個縣城智能有且隻有有其中的一種狀态,即:
建立(New):建立後尚未啟動的線程;
運作(Runable):包括了作業系統線程狀态中的Running和Ready,處于此狀态的線程可能正在執行,也可能正在等待CPU為它配置設定執行時間;
無限期等待(Waiting):該狀态的線程不會被配置設定CPU執行時間,他們要等待其他線程顯式喚醒。以下方式可以讓線程陷入Waiting狀态:
1.沒有設定Timeout參數的Object.wat()方法;
2.沒有設定Timeout參數的Thread.join()方法;
3.LockSupport.park()方法。
限制等待(Timed Waiting):該狀态的線程也不會被配置設定CPU執行時間,不過無須等待其他線程顯示喚醒,在一定時間之後它們會由系統自動喚醒。以下方式可以讓線程陷入Timed Waiting狀态:
1.Thread.sleep()方法;
2.設定了Timeout參數的Ojbect.wait()方法;
3.設定了Timeout參數的Thread.join()方法;
4.LockSupport.parkNanos()方法;
5.LockSupport.parkUntil()方法。
阻塞(Blocked):線程被阻塞。在程式等待進入同步區域時,線程進入這種狀态。
結束(Terminated):終止線程的狀态。
<a target="_blank" href="http://blog.51cto.com/attachment/201306/223150342.png"></a>
本文轉自 LinkedKeeper 51CTO部落格,原文連結:http://blog.51cto.com/sauron/1228565,如需轉載請自行聯系原作者