亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Java內存模型JMM

2019-11-06 06:14:12
字體:
來源:轉載
供稿:網友

多任務和高并發的內存交互

多任務和高并發是衡量一臺計算機處理器的能力重要指標之一。一般衡量一個服務器性能的高低好壞,使用每秒事務處理數(Transactions Per Second,TPS)這個指標比較能說明問題,它代表著一秒內服務器平均能響應的請求數,而TPS值與程序的并發能力有著非常密切的關系。物理機的并發問題與虛擬機中的情況有很多相似之處,物理機對并發的處理方案對于虛擬機的實現也有相當大的參考意義。

由于計算機的存儲設備與處理器的運算能力之間有幾個數量級的差距,所以現代計算機系統都不得不加入一層讀寫速度盡可能接近處理器運算速度的高速緩存(cache)來作為內存與處理器之間的緩沖:將運算需要使用到的數據復制到緩存中,讓運算能快速進行,當運算結束后再從緩存同步回內存之中,這樣處理器就無需等待緩慢的內存讀寫了。

基于高速緩存的存儲交互很好地解決了處理器與內存的速度矛盾,但是引入了一個新的問題:緩存一致性(Cache Coherence)。在多處理器系統中,每個處理器都有自己的高速緩存,而他們又共享同一主存,如下圖所示:多個處理器運算任務都涉及同一塊主存,需要一種協議可以保障數據的一致性,這類協議有MSI、MESI、MOSI及Dragon PRotocol等。

物理機內存交互關系

除此之外,為了使得處理器內部的運算單元能盡可能被充分利用,處理器可能會對輸入代碼進行亂序執行(Out-Of-Order Execution)優化,處理器會在計算之后將對亂序執行的代碼進行結果重組,保證結果準確性。與處理器的亂序執行優化類似,java虛擬機的即時編譯器中也有類似的指令重排序(Instruction Recorder)優化。

Java內存模型

內存模型可以理解為在特定的操作協議下,對特定的內存或者高速緩存進行讀寫訪問的過程抽象,不同架構下的物理機擁有不一樣的內存模型,Java虛擬機也有自己的內存模型,即Java內存模型(Java Memory Model, JMM)。在C/C++語言中直接使用物理硬件和操作系統內存模型,導致不同平臺下并發訪問出錯。而JMM的出現,能夠屏蔽掉各種硬件和操作系統的內存訪問差異,實現平臺一致性,是的Java程序能夠“一次編寫,到處運行”。

主內存和工作內存

Java內存模型的主要目標是定義程序中各個變量的訪問規則,即在虛擬機中將變量存儲到內存和從內存中取出變量這樣底層細節。此處的變量與Java編程時所說的變量不一樣,指包括了實例字段、靜態字段和構成數組對象的元素,但是不包括局部變量與方法參數,后者是線程私有的,不會被共享。

Java內存模型中規定了所有的變量都存儲在主內存中,每條線程還有自己的工作內存(可以與前面講的處理器的高速緩存類比),線程的工作內存中保存了該線程使用到的變量到主內存副本拷貝,線程對變量的所有操作(讀取、賦值)都必須在工作內存中進行,而不能直接讀寫主內存中的變量。不同線程之間無法直接訪問對方工作內存中的變量,線程間變量值的傳遞均需要在主內存來完成,線程、主內存和工作內存的交互關系如下圖所示,和上圖很類似。

虛擬機內存交互關系

注意:這里的主內存、工作內存與Java內存區域的Java堆、棧、方法區不是同一層次內存劃分,這兩者基本上沒有關系。

內存交互操作

由上面的交互關系可知,關于主內存與工作內存之間的具體交互協議,即一個變量如何從主內存拷貝到工作內存、如何從工作內存同步到主內存之間的實現細節,Java內存模型定義了以下八種操作來完成:

lock(鎖定):作用于主內存的變量,把一個變量標識為一條線程獨占狀態。unlock(解鎖):作用于主內存變量,把一個處于鎖定狀態的變量釋放出來,釋放后的變量才可以被其他線程鎖定。read(讀?。鹤饔糜谥鲀却孀兞?,把一個變量值從主內存傳輸到線程的工作內存中,以便隨后的load動作使用load(載入):作用于工作內存的變量,它把read操作從主內存中得到的變量值放入工作內存的變量副本中。use(使用):作用于工作內存的變量,把工作內存中的一個變量值傳遞給執行引擎,每當虛擬機遇到一個需要使用變量的值的字節碼指令時將會執行這個操作。assign(賦值):作用于工作內存的變量,它把一個從執行引擎接收到的值賦值給工作內存的變量,每當虛擬機遇到一個給變量賦值的字節碼指令時執行這個操作。store(存儲):作用于工作內存的變量,把工作內存中的一個變量的值傳送到主內存中,以便隨后的write的操作。write(寫入):作用于主內存的變量,它把store操作從工作內存中一個變量的值傳送到主內存的變量中。

如果要把一個變量從主內存中復制到工作內存,就需要按順尋地執行read和load操作,如果把變量從工作內存中同步回主內存中,就要按順序地執行store和write操作。Java內存模型只要求上述兩個操作必須按順序執行,而沒有保證必須是連續執行。也就是read和load之間,store和write之間是可以插入其他指令的,如對主內存中的變量a、b進行訪問時,可能的順序是read a,read b,load b, load a。Java內存模型還規定了在執行上述八種基本操作時,必須滿足如下規則:

不允許read和load、store和write操作之一單獨出現不允許一個線程丟棄它的最近assign的操作,即變量在工作內存中改變了之后必須同步到主內存中。不允許一個線程無原因地(沒有發生過任何assign操作)把數據從工作內存同步回主內存中。一個新的變量只能在主內存中誕生,不允許在工作內存中直接使用一個未被初始化(load或assign)的變量。即就是對一個變量實施use和store操作之前,必須先執行過了assign和load操作。一個變量在同一時刻只允許一條線程對其進行lock操作,lock和unlock必須成對出現如果對一個變量執行lock操作,將會清空工作內存中此變量的值,在執行引擎使用這個變量前需要重新執行load或assign操作初始化變量的值如果一個變量事先沒有被lock操作鎖定,則不允許對它執行unlock操作;也不允許去unlock一個被其他線程鎖定的變量。對一個變量執行unlock操作之前,必須先把此變量同步到主內存中(執行store和write操作)。

這8種內存訪問操作很繁瑣,后文會使用一個等效判斷原則,即先行發生(happens-before)原則來確定一個內存訪問在并發環境下是否安全。

volatile變量規則

關鍵字volatile是JVM中最輕量的同步機制。volatile變量具有2種特性:

保證變量的可見性。對一個volatile變量的讀,總是能看到(任意線程)對這個volatile變量最后的寫入,這個新值對于其他線程來說是立即可見的。屏蔽指令重排序:指令重排序是編譯器和處理器為了高效對程序進行優化的手段,下文有詳細的分析。

volatile語義并不能保證變量的原子性。對任意單個volatile變量的讀/寫具有原子性,但類似于i++、i–這種復合操作不具有原子性,因為自增運算包括讀取i的值、i值增加1、重新賦值3步操作,并不具備原子性。

由于volatile只能保證變量的可見性和屏蔽指令重排序,只有滿足下面2條規則時,才能使用volatile來保證并發安全,否則就需要加鎖(使用synchronized、lock或者java.util.concurrent中的Atomic原子類)來保證并發中的原子性。

運算結果不存在數據依賴(重排序的數據依賴性),或者只有單一的線程修改變量的值(重排序的as-if-serial語義)變量不需要與其他的狀態變量共同參與不變約束

因為需要在本地代碼中插入許多內存屏蔽指令在屏蔽特定條件下的重排序,volatile變量的寫操作與讀操作相比慢一些,但是其性能開銷比鎖低很多。

long/double非原子協定

JMM要求lock、unlock、read、load、assign、use、store、write這8個操作都必須具有原子性,但對于64為的數據類型(long和double,具有非原子協定:允許虛擬機將沒有被volatile修飾的64位數據的讀寫操作劃分為2次32位操作進行。(與此類似的是,在棧幀結構的局部變量表中,long和double類型的局部變量可以使用2個能存儲32位變量的變量槽(Variable Slot)來存儲的,關于這一部分的詳細分析,詳見詳見周志明著《深入理解Java虛擬機》8.2.1節)

如果多個線程共享一個沒有聲明為volatile的long或double變量,并且同時讀取和修改,某些線程可能會讀取到一個既非原值,也不是其他線程修改值的代表了“半個變量”的數值。不過這種情況十分罕見。因為非原子協議換句話說,同樣允許long和double的讀寫操作實現為原子操作,并且目前絕大多數的虛擬機都是這樣做的。

原子性、可見性、有序性

原子性

JMM保證的原子性變量操作包括read、load、assign、use、store、write,而long、double非原子協定導致的非原子性操作基本可以忽略。如果需要對更大范圍的代碼實行原子性操作,則需要JMM提供的lock、unlock、synchronized等來保證。

可見性

前面分析volatile語義時已經提到,可見性是指當一個線程修改了共享變量的值,其他線程能夠立即得知這個修改。JMM在變量修改后將新值同步回主內存,依賴主內存作為媒介,在變量被線程讀取前從內存刷新變量新值,保證變量的可見性。普通變量和volatile變量都是如此,只不過volatile的特殊規則保證了這種可見性是立即得知的,而普通變量并不具備這種嚴格的可見性。除了volatile外,synchronized和final也能保證可見性。

有序性

JMM的有序性表現為:如果在本線程內觀察,所有的操作都是有序的;如果在一個線程中觀察另一個線程,所有的操作都是無序的。前半句指“線程內表現為串行的語義”(as-if-serial),后半句值“指令重排序”和普通變量的”工作內存與主內存同步延遲“的現象。

重排序

在執行程序時為了提高性能,編譯器和處理器經常會對指令進行重排序。從硬件架構上來說,指令重排序是指CPU采用了允許將多條指令不按照程序規定的順序,分開發送給各個相應電路單元處理,而不是指令任意重排。重排序分成三種類型:

編譯器優化的重排序。編譯器在不改變單線程程序語義放入前提下,可以重新安排語句的執行順序。指令級并行的重排序?,F代處理器采用了指令級并行技術來將多條指令重疊執行。如果不存在數據依賴性,處理器可以改變語句對應機器指令的執行順序。內存系統的重排序。由于處理器使用緩存和讀寫緩沖區,這使得加載和存儲操作看上去可能是在亂序執行。

重排序

JMM的重排序屏障

從Java源代碼到最終實際執行的指令序列,會經過三種重排序。但是,為了保證內存的可見性,Java編譯器在生成指令序列的適當位置會插入內存屏障指令來禁止特定類型的處理器重排序。對于編譯器的重排序,JMM會根據重排序規則禁止特定類型的編譯器重排序;對于處理器重排序,JMM會插入特定類型的內存屏障,通過內存的屏障指令禁止特定類型的處理器重排序。這里討論JMM對處理器的重排序,為了更深理解JMM對處理器重排序的處理,先來認識一下常見處理器的重排序規則:

重排序屏障

其中的N標識處理器不允許兩個操作進行重排序,Y表示允許。其中Load-Load表示讀-讀操作、Load-Store表示讀-寫操作、Store-Store表示寫-寫操作、Store-Load表示寫-讀操作??梢钥闯觯撼R娞幚砥鲗?讀操作都是允許重排序的,并且常見的處理器都不允許對存在數據依賴的操作進行重排序(對應上面數據轉換那一列,都是N,所以處理器不允許這種重排序)。

那么這個結論對我們有什么作用呢?比如第一點:處理器允許寫-讀操作兩者之間的重排序,那么在并發編程中讀線程讀到可能是一個未被初始化或者是一個NULL等,出現不可預知的錯誤,基于這點,JMM會在適當的位置插入內存屏障指令來禁止特定類型的處理器的重排序。內存屏障指令一共有4類:

LoadLoad Barriers:確保Load1數據的裝載先于Load2以及所有后續裝載指令StoreStore Barriers:確保Store1的數據對其他處理器可見(會使緩存行無效,并刷新到內存中)先于Store2及所有后續存儲指令的裝載LoadStore Barriers:確保Load1數據裝載先于Store2及所有后續存儲指令刷新到內存StoreLoad Barriers:確保Store1數據對其他處理器可見(刷新到內存,并且其他處理器的緩存行無效)先于Load2及所有后續裝載指令的裝載。該指令會使得該屏障之前的所有內存訪問指令完成之后,才能執行該屏障之后的內存訪問指令。

數據依賴性

根據上面的表格,處理器不會對存在數據依賴的操作進行重排序。這里數據依賴的準確定義是:如果兩個操作同時訪問一個變量,其中一個操作是寫操作,此時這兩個操作就構成了數據依賴。常見的具有這個特性的如i++、i—。如果改變了具有數據依賴的兩個操作的執行順序,那么最后的執行結果就會被改變。這也是不能進行重排序的原因。例如:

寫后讀:a = 1; b = a;寫后寫:a = 1; a = 2;讀后寫:a = b; b = 1;

重排序遵守數據依賴性,編譯器和處理器不會改變存在數據依賴關系的兩個操作的執行順序。但是這里所說的數據依賴性僅針對單個處理器中執行的指令序列和單個線程中執行的操作,不同處理器之間和不同線程之間的數據依賴性不被編譯器和處理器考慮。

as-if-serial語義

as-if-serial語義的意思指:管怎么重排序(編譯器和處理器為了提高并行度),(單線程)程序的執行結果不能被改變。編譯器,runtime 和處理器都必須遵守as-if-serial語義。

as-if-serial語義把單線程程序保護了起來,遵守as-if-serial語義的編譯器,runtime 和處理器共同為編寫單線程程序的程序員創建了一個幻覺:單線程程序是按程序的順序來執行的。as-if-serial語義使單線程程序員無需擔心重排序會干擾他們,也無需擔心內存可見性問題。

重排序對多線程的影響

如果代碼中存在控制依賴的時候,會影響指令序列執行的并行度(因為高效)。也是為此,編譯器和處理器會采用猜測(Speculation)執行來克服控制的相關性。所以重排序破壞了程序順序規則(該規則是說指令執行順序與實際代碼的執行順序是一致的,但是處理器和編譯器會進行重排序,只要最后的結果不會改變,該重排序就是合理的)。

在單線程程序中,由于as-ifserial語義的存在,對存在控制依賴的操作重排序,不會改變執行結果;但在多線程程序中,對存在控制依賴的操作重排序,可能會改變程序的執行結果。

先行發生原則(happens-before)

前面所述的內存交互操作必須要滿足一定的規則,而happens-before就是定義這些規則的一個等效判斷原則。happens-before是JMM定義的2個操作之間的偏序關系:如果操作A線性發生于操作B,則A產生的影響能被操作B觀察到,“影響”包括修改了內存中共享變量的值、發送了消息、調用了方法等。如果兩個操作滿足happens-before原則,那么不需要進行同步操作,JVM能夠保證操作具有順序性,此時不能夠隨意的重排序。否則,無法保證順序性,就能進行指令的重排序。

happens-before原則主要包括:

程序次序規則(Program Order Rule):在同一個線程中,按照程序代碼順序,書寫在前面的操作先行發生于書寫在后面的操縱。準確的說是程序的控制流順序,考慮分支和循環等。管理鎖定規則(Monitor Lock Rule):一個unlock操作先行發生于后面(時間上的順序)對同一個鎖的lock操作。volatile變量規則(Volatile Variable Rule):對一個volatile變量的寫操作先行發生于后面(時間上的順序)對該變量的讀操作。線程啟動規則(Thread Start Rule):Thread對象的start()方法先行發生于此線程的每一個動作。線程終止規則(Thread Termination Rule):線程的所有操作都先行發生于對此線程的終止檢測,可以通過Thread.join()方法結束、Thread.isAlive()的返回值等手段檢測到線程已經終止執行。線程中斷規則(Thread Interruption Rule):對線程interrupt()方法的調用先行發生于被中斷線程的代碼檢測到中斷時事件的發生。Thread.interrupted()可以檢測是否有中斷發生。對象終結規則(Finilizer Rule):一個對象的初始化完成(構造函數執行結束)先行發生于它的finalize()的開始。傳遞性(Transitivity):如果操作A 先行發生于操作B,操作B 先行發生于操作C,那么可以得出A 先行發生于操作C。

注意:不同操作時間先后順序與先行發生原則之間沒有關系,二者不能相互推斷,衡量并發安全問題不能受到時間順序的干擾,一切都要以happens-before原則為準

示例代碼1:

private int value = 0;public void setValue(int value) {    this.value = value;}public int getValue() {    return this.value;}

對于上面的代碼,假設線程A在時間上先調用setValue(1),然后線程B調用getValue()方法,那么線程B收到的返回值一定是1嗎?

按照happens-before原則,兩個操作不在同一個線程、沒有通道鎖同步、線程的相關啟動、終止和中斷以及對象終結和傳遞性等規則都與此處沒有關系,因此這兩個操作是不符合happens-before原則的,這里的并發操作是不安全的,返回值并不一定是1。

對于該問題的修復,可以使用lock或者synchronized套用“管程鎖定規則”實現先行發生關系;或者將value定義為volatile變量(兩個方法的調用都不存在數據依賴性),套用“volatile變量規則”實現先行發生關系。如此一來,就能保證并發安全性。

示例代碼2

// 以下操作在同一個線程中int i = 1;int j = 2;

上面的代碼符合“程序次序規則”,滿足先行發生關系,但是第2條語句完全可能由于重排序而被處理器先執行,時間上先于第1條語句。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美二区在线播放| 国产精品福利无圣光在线一区| 国产成人91久久精品| 亚洲一区二区三区久久| 欧美精品手机在线| 97视频在线观看成人| 97在线免费观看视频| 国产精品视频久久久久| 久久香蕉频线观| 国产玖玖精品视频| 日本高清久久天堂| 亚洲成成品网站| 成人免费高清完整版在线观看| 免费成人高清视频| 色婷婷**av毛片一区| 亚洲第一网中文字幕| 欧美一区三区三区高中清蜜桃| 国产中文字幕91| 欧美激情按摩在线| 久久免费在线观看| 九九久久精品一区| 久久久久99精品久久久久| 亚洲国产精久久久久久久| 亚洲精品国产精品国自产在线| 在线电影中文日韩| 亚洲第一黄色网| 国产91精品最新在线播放| 成人在线免费观看视视频| 亚洲欧洲高清在线| 久久99国产综合精品女同| 精品欧美激情精品一区| 国产视频一区在线| 国外视频精品毛片| 91九色单男在线观看| 91免费在线视频| 久久中文字幕一区| 色偷偷噜噜噜亚洲男人的天堂| 日韩精品极品视频| 亚洲精品网站在线播放gif| 欧美成人全部免费| 亚洲精品久久在线| 2019中文字幕在线免费观看| 欧美老妇交乱视频| 日韩一区视频在线| 欧美一级黑人aaaaaaa做受| 成人免费视频97| xvideos亚洲人网站| 这里只有精品视频在线| 国产91在线播放精品91| 欧美电影在线观看完整版| 国产a∨精品一区二区三区不卡| 中国日韩欧美久久久久久久久| 亚洲成人av资源网| 在线看日韩av| 欧美精品制服第一页| 日产精品99久久久久久| 亚洲欧美制服另类日韩| 日韩在线www| 国产亚洲精品久久久久久| 国产成人亚洲综合91精品| 欧美国产第二页| 国产精品无码专区在线观看| 国内揄拍国内精品少妇国语| 51视频国产精品一区二区| 亚洲精品国产suv| 亚洲高清福利视频| 亚洲欧美日韩一区二区在线| 亚洲丝袜一区在线| 亚洲午夜久久久久久久| 亚洲国产精久久久久久| 韩国v欧美v日本v亚洲| 国产午夜精品美女视频明星a级| 亚洲人午夜精品| 欧美成人高清视频| 国产精品91久久久| 欧美激情久久久| 社区色欧美激情 | 亚洲第一区中文99精品| 亚洲国产精久久久久久| 日韩精品久久久久| 亚洲欧美视频在线| 人九九综合九九宗合| 九九热这里只有在线精品视| 国产精品吹潮在线观看| 亚洲国产精品嫩草影院久久| 黑丝美女久久久| 一区二区三区四区在线观看视频| 亚洲第一中文字幕在线观看| 精品国模在线视频| 成人免费激情视频| 欧美交受高潮1| 2018中文字幕一区二区三区| 久久久久免费精品国产| 亚洲人线精品午夜| 国产精品久久久久福利| 91欧美精品午夜性色福利在线| 欧美人与性动交a欧美精品| zzjj国产精品一区二区| 亚洲欧美激情另类校园| 欧美肥老妇视频| 成人天堂噜噜噜| 国产精品自拍小视频| 成人做爽爽免费视频| 国产精品成人av性教育| 成人乱人伦精品视频在线观看| 国产精品v片在线观看不卡| 在线播放精品一区二区三区| 久久99青青精品免费观看| 大桥未久av一区二区三区| 中文字幕无线精品亚洲乱码一区| 久久精品国产一区二区电影| 日韩久久精品成人| 亚洲尤物视频网| 亚洲欧美日韩高清| 日本不卡视频在线播放| 精品丝袜一区二区三区| 色噜噜狠狠狠综合曰曰曰| 国产精品网站入口| 日韩av123| 欧美视频在线观看 亚洲欧| 亚洲综合中文字幕在线观看| 日韩视频欧美视频| 国产不卡一区二区在线播放| 亚洲伊人久久大香线蕉av| 亚洲欧洲成视频免费观看| 精品国产91乱高清在线观看| 欧美久久精品一级黑人c片| 亚洲精品久久久久久久久久久| 欧美性猛交xxxx偷拍洗澡| 亚洲成成品网站| 国产精品国产自产拍高清av水多| 国产精品老牛影院在线观看| 日韩欧美在线视频日韩欧美在线视频| 国外成人在线直播| www.xxxx欧美| 国产精品美女www爽爽爽视频| 精品欧美国产一区二区三区| 国产欧美最新羞羞视频在线观看| 国外视频精品毛片| 成人在线一区二区| 亚洲一区二区福利| 成人黄色短视频在线观看| 中文字幕日韩电影| 欧美日韩国产一区中文午夜| 亚洲 日韩 国产第一| 精品日本美女福利在线观看| 亚洲欧美日韩精品| 亚洲深夜福利网站| 精品亚洲男同gayvideo网站| 成人精品一区二区三区| 在线丨暗呦小u女国产精品| 欧美裸体视频网站| 日韩在线视频中文字幕| 欧美三级欧美成人高清www| 欧美做受高潮1| 自拍视频国产精品| 欧美国产视频日韩| 91在线观看欧美日韩| 国产噜噜噜噜久久久久久久久| 欧美一区深夜视频| 亚洲美女av电影| 亚洲精品电影网在线观看| 欧美视频二区36p| 欧美亚洲另类制服自拍|