java多線程詳解一線程的內存模型和線程特性

這幾天面試互聯網公司的高級java工程師,多線程問的相對而言比較多。因此,從各類角度來看看java中多線程的實現方式。java

一.Java多線程中的內存模型

1.java主內存和工做內存

根據java內存模型,java中全部的變量都存儲在主內存中(main memory),每條線程還有本身的工做內存(Working Memory),線程的工做內存中保存了主內存的副本拷貝,線程對全部變量的操做都必須在工做內存中進行而不能操做主內存的變量。不一樣的線程不能訪問別的線程工做內存中的變量,線程之間的變量值傳遞必需要經過主內存來完成,線程、主內存、工做內存三者的交互關係以下圖所示:面試

2.內存之間的交互操做

java內存模型定義了8種不一樣操做來完成,虛擬機實現時候必須保證這8種操做都是原子的、不可再分的。多線程

lock(鎖定):主要做用於主內存變量,它把一個變量標誌爲一條線程獨佔的狀態。app

unlock(解鎖):做用於主內存變量,它將處於一個鎖定狀態的變量釋放出來,釋放出來的內存變量才能被其餘線程鎖定。this

read(讀取):做用於主內存的變量,它把一個變量的值從主內存中運輸到線程的工做內存中,以便隨後的load指令使用。spa

laod(載入):做用於工做內存的變量,它把主內存中讀到的變量放入工做內存變量的副本中。線程

use(使用):做用於工做內存中的變量,它把工做內存中的一個變量值傳遞給執行引擎,每當虛擬機遇到一個須要使用變量值的字節碼指令時候回執行這個操做。blog

assign(賦值):做用於工做內存變量,它把一個從執行引擎接受到的值賦給工做內存中的變量,每當虛擬機遇到一個給變量賦值的字節碼的時候執行這個操做。排序

store(存儲):做用於工做內存中的變量,它把工做內存中的一個變量送到主內存中,以便之後的write操做使用。內存

write(寫入):做用於主內存中,它把store操做從工做內存中獲得的變量的值放入主內存中。

 

2.多線程中的原子性、可見性、有序性

1.原子性

原子性:由java內存模型來直接保證原子性的操做包括read、load、assign、use、store和write。基本數據類型訪問具備原子性(除了long 和double類型特殊的非原子協定)。

若是須要更大範圍的原子性操做的時候,java內訓模型還提供了lock()和unlock()操做來完成這種需求。在字節碼層次上提供了monitorebter和moniterexit來隱式的使用這個操做,這兩個字節碼反映到java代碼中就是同步代碼塊--sychronized關鍵字。

2.可見性

可見性:是指當一個線程修改了共享變量的值,其餘線程可以當即得知這個修改。

java內存模型是經過變量在修改後的新值同步回主內存中,在變量讀取前從主內存刷新變量值住,這種依賴 主內存做爲傳遞媒介的方式來實現可見性的。經過volatile保證了線程之間的可見性。一樣還有synchronized 和final 來實現線程可見性。

同步代碼塊的可見性是由「對一個變量執行unlock操做以前,必須先把此變量同步到主內存中(執行store 和 write操做)」。被final修飾的普通變量在構造器中一旦初始化完成,而且構造器沒有把"this"關鍵字的引用傳遞出去,那麼在其餘線程中就能看見final關鍵字的值。

3.有序性

有序性:在java語言中提供了volatile和synchronized倆個關鍵字來保證線程之間操做是有序性,volatile關鍵字自己包含了禁止指令重排序的語義,而sychronized則是由「一個變量在同一時刻只容許一個線程進行lock操做」,這條規則決定了持有同一個鎖的同步代碼塊只能串行地進入。

四、happen-before原則

相關文章
相關標籤/搜索