java高效并發(fā)學(xué)習(xí)筆記(一)java內(nèi)存模型

java高效并發(fā)學(xué)習(xí)筆記(一)java內(nèi)存模型

學(xué)習(xí)JVM+JAVA多線程中,學(xué)習(xí)的書籍是《深入理解java虛擬機(jī)》——周志明

這里記錄一些筆記以便日后經(jīng)常學(xué)習(xí)回顧。

學(xué)習(xí)java虛擬機(jī)的并發(fā)之前,了解了物理計(jì)算機(jī)中并發(fā)的一些處理情況。計(jì)算機(jī)在處理運(yùn)算任務(wù)的時(shí)候加入了高速緩存來調(diào)和處理器以及內(nèi)存之間不同數(shù)量級(jí)導(dǎo)致的耗時(shí)問題:將需要運(yùn)算的數(shù)據(jù)復(fù)制到緩存中,然后進(jìn)行高速運(yùn)算,之后再由緩存同步回內(nèi)存中。在java虛擬機(jī)中,定義了一種java內(nèi)存模型,可以類比物理計(jì)算機(jī)的這種處理方式。

主內(nèi)存與工作內(nèi)存

java虛擬機(jī)的內(nèi)存模型規(guī)定了所有的變量都存儲(chǔ)在主內(nèi)存中,線程對(duì)變量的操作都必須在工作內(nèi)存中進(jìn)行,而不能直接讀寫主內(nèi)存中的變量。不同線程不能訪問對(duì)方的工作內(nèi)存。

內(nèi)存之間的交互操作

根據(jù)上面所說,線程操作都是在工作內(nèi)存中,所以就存在主內(nèi)存和工作內(nèi)存之間的操作情況,也就是說一個(gè)變量怎么才能從主內(nèi)存中拷貝到工作內(nèi)存中,而工作內(nèi)存中的變量在線程操作完之后又是怎么寫回主內(nèi)存的。java內(nèi)存模型規(guī)定了8中操作來完成上述的情況,而且這8中操作都是原子性的。

lock(鎖定):作用于主內(nèi)存的變量,它將一個(gè)變量標(biāo)識(shí)為一條線程獨(dú)占的狀態(tài)。

unlock(解鎖):作用于主內(nèi)存的變量,它將一個(gè)處于鎖定狀態(tài)的變量釋放出來,釋放后的變量才可以被其他線程鎖定。

read(讀取):作用于主內(nèi)存的變量,它把一個(gè)變量的值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存,以便之后的load動(dòng)作使用。

load(載入):作用于工作內(nèi)存的變量,它把read動(dòng)作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中。

use(使用):作用于工作內(nèi)存的變量,它把工作內(nèi)存中一個(gè)變量的值傳遞給執(zhí)行引擎,每當(dāng)虛擬機(jī)遇到一個(gè)需要使用到變量的值的字節(jié)碼指令時(shí)將會(huì)執(zhí)行操作。

assign(賦值):作用于工作內(nèi)存的變量,它把一個(gè)從執(zhí)行引擎接收到的值賦給工作內(nèi)存的變量,每當(dāng)虛擬機(jī)遇到一個(gè)給變量賦值的字節(jié)碼指令時(shí)執(zhí)行這個(gè)操作。

store(存儲(chǔ)):作用于工作內(nèi)存的變量,它把工作內(nèi)存中一個(gè)變量的值傳送到主內(nèi)存中,以便隨后的write動(dòng)作。

write(寫入):作用于主內(nèi)存的變量,它把store操作從工作內(nèi)存中得到的變量的值放入主內(nèi)存的變量中。

以上8個(gè)操作是內(nèi)存模型規(guī)定的基本操作,其中read與load、store與write是成對(duì)出現(xiàn)的。

當(dāng)一個(gè)線程對(duì)某一變量進(jìn)行操作時(shí),如果此時(shí)有其他線程需要得到該變量的值,那么在上一線程沒有將變量同步回主內(nèi)存中時(shí),此時(shí)后一線程所得到的該變量的值就是不確定的,于是就有了volatile。

volatile

volatile是java虛擬機(jī)提供的最輕量級(jí)的同步機(jī)制,該關(guān)鍵字實(shí)現(xiàn)了兩個(gè)功能:保證被修飾變量對(duì)所有線程的可見性;禁止指令重排序優(yōu)化。

書中有詳細(xì)的解釋,這里就寫一些簡單的筆記記錄吧。

首先對(duì)于可見性的理解,volatile的可見性無法保證原子性,在一下兩種情況下可以使用:運(yùn)算結(jié)果并不依賴變量的當(dāng)前值,或者能夠保證只有單一的線程修改變量的值;變量不需要與其他的狀態(tài)變量共同參與不變約束。

對(duì)于禁止指令重排序的理解,指令重排序是指CPU可以不按照程序規(guī)定的順序?qū)⒍鄺l指令分發(fā)給相應(yīng)的電路單元處理。

原子性、可見性、有序性

關(guān)于這些特性,需要了解那些操作實(shí)現(xiàn)了這3種特性。

原子性:java內(nèi)存模型的操作保證了原子性。當(dāng)然lock與unlock提供了更大范圍的原子性,反映到j(luò)ava代碼中就是同步塊——synchronized關(guān)鍵字。

可見性:可見性就是當(dāng)一個(gè)線程修改了共享變量的值,其他線程能夠立刻得知這個(gè)修改。volatile就實(shí)現(xiàn)了可見性,當(dāng)然實(shí)現(xiàn)了可見性的還有synchronized和final。synchronized的原理是因?yàn)閳?zhí)行unlock之前必須將變量同步回主內(nèi)存。而final的原理是被修飾的字段在構(gòu)造器中一旦初始化完成,并且構(gòu)造器沒有把this的引用傳遞出去,那么在其他線程中就能看到final字段的值。

有序性:在本線程中,所有的操作都是有序的;在一個(gè)線程中觀察另一個(gè)線程,所有的操作都是無序的。而實(shí)現(xiàn)有序操作的方法有volatile和synchronized。volatile是由于其禁止指令重排序,synchronized是因?yàn)橐粋€(gè)變量在同一時(shí)刻只允許一條線程對(duì)其進(jìn)行l(wèi)ock操作。

先行先發(fā)原則

在判斷數(shù)據(jù)是否存在競(jìng)爭(zhēng)、線程是否安全中,主要依靠了這個(gè)原則。

先行先發(fā)原則是java內(nèi)存模型中定義的兩項(xiàng)操作之間的偏序關(guān)系,如果說操作A先行發(fā)生于B,其實(shí)就是說發(fā)生操作B之前,操作A產(chǎn)生的影響能被B觀察到。比如:

i=1;

j=i;

i=2;

假設(shè)線程A中的操作i=1先行發(fā)生于線程B中的操作j=i,那么可以確定線程B的操作之后j的值一定等于1。現(xiàn)在加入C線程,依然保持線程A和線程B之間的先行發(fā)生關(guān)系,而線程C出現(xiàn)在線程A和線程B操作之間,但是線程C與線程B沒有先行發(fā)生關(guān)系,那么j的值是多少呢?答案不確定,可能是1也可能是2,因?yàn)榫€程C的操作對(duì)于線程B來說可以被觀察到,也可能不會(huì)。這種情況便需要保證同步,因?yàn)椴痪邆涠嗑€程的安全性。(時(shí)間先后順序與先行發(fā)生原則之間基本沒有太大關(guān)系,所以在衡量并發(fā)安全問題的時(shí)候不要受到時(shí)間順序的干擾,一切必須以先行發(fā)生原則為準(zhǔn)。)

java內(nèi)存模型下有一些先行發(fā)生關(guān)系,無需任何的同步器協(xié)助就可以直接使用。如果兩個(gè)操作時(shí)間關(guān)系不在此列,并且無法從下列規(guī)則推導(dǎo)出來的話,它們就沒有順序性保障。

程序次序規(guī)則:在一個(gè)線程內(nèi),按照程序代碼順序,寫在前面的操作先行發(fā)生與寫在后面的操作。

管理鎖定規(guī)則:一個(gè)unlock操作先行發(fā)生與后面對(duì)同一個(gè)鎖的lock操作。

線程啟動(dòng)規(guī)則:Thread對(duì)象的start()方法先行發(fā)生于此線程的每一個(gè)動(dòng)作。

線程終止規(guī)則:線程中所有操作都先行于對(duì)此線程的終止檢測(cè),我們可以通過Thread.join()方法結(jié)束、Thread.isAlive()的返回值等手段檢測(cè)到線程已經(jīng)終止執(zhí)行。

線程終端規(guī)則:對(duì)線程interrupt()方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測(cè)到中斷事件的發(fā)生。

對(duì)象終結(jié)規(guī)則:一個(gè)對(duì)象的初始化完成先行發(fā)生于它的finalize()方法的開始。

volatile變量規(guī)則:對(duì)一個(gè)volatile變量的寫操作先行發(fā)生于后面對(duì)這個(gè)變量的讀操作。

傳遞性:A先行發(fā)生于B,B先行發(fā)生于C,則A先行發(fā)生與C。

發(fā)布于 2017-08-16

著作權(quán)歸作者所有

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容