這篇文章主要介紹“Happens-Before原則和As-If-Serial語義是什么”,在日常操作中,相信很多人在Happens-Before原則和As-If-Serial語義是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Happens-Before原則和As-If-Serial語義是什么”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
創(chuàng)新互聯(lián)長期為數(shù)千家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為無棣企業(yè)提供專業(yè)的成都網(wǎng)站建設(shè)、做網(wǎng)站,無棣網(wǎng)站改版等技術(shù)服務(wù)。擁有十余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。
Java內(nèi)存模型是共享內(nèi)存的并發(fā)模型,線程之間主要通過讀-寫共享變量來完成隱式通信。
Java中的共享變量是存儲在內(nèi)存中的,多個(gè)線程由其工作內(nèi)存,其工作方式是將共享內(nèi)存中的變量拿出來放在工作內(nèi)存,操作完成后,再將最新的變量放回共享變量,這時(shí)其他的線程就可以獲取到最新的共享變量。
從橫向去看看,線程A和線程B就好像通過共享變量在進(jìn)行隱式通信。這其中有很有意思的問題,如果線程A更新后數(shù)據(jù)并沒有及時(shí)寫回到主存,而此時(shí)線程B讀到的是過期的數(shù)據(jù),這就出現(xiàn)了 “臟讀” 現(xiàn)象。
為避免臟讀,可以通過同步機(jī)制(控制不同線程間操作發(fā)生的相對順序)來解決或者通過volatile關(guān)鍵字使得每次volatile變量都能夠強(qiáng)制刷新到主存,從而對每個(gè)線程都是可見的。
執(zhí)行程序時(shí),為了提高性能,編譯器和處理器常常會對指令進(jìn)行重排序。一般重排序可以分為如下三種:如圖,1.屬于編譯器重排序,而2和3統(tǒng)稱為處理器重排序。
這些重排序會導(dǎo)致線程安全的問題,一個(gè)很經(jīng)典的例子就是DCL問題。JMM的編譯器重排序規(guī)則會禁止一些特定類型的編譯器重排序;針對處理器重排序,編譯器在生成指令序列的時(shí)候會通過插入內(nèi)存屏障指令來禁止某些特殊的處理器重排序。
(1)編譯器優(yōu)化的重排序:編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執(zhí)行順序;
(2)指令級并行的重排序:現(xiàn)代處理器采用指令級并行技術(shù)來將多條指令重疊執(zhí)行。如果不存在數(shù)據(jù)依賴性,處理器可以改變語句對應(yīng)機(jī)器指令的執(zhí)行順序;
(3)內(nèi)存系統(tǒng)的重排序。由于處理器使用緩存和讀/寫緩沖區(qū),這使得加載和存儲操作看上去可能是在亂序執(zhí)行的。
public double rectangleArea(double length , double width){ double leng; double wid; leng=length;//A wid=width;//B double area=leng*wid;//C return area; }
由于A,B之間沒有任何關(guān)系,對最終結(jié)果也不會存在關(guān)系,它們之間執(zhí)行順序可以重排序。因此可以執(zhí)行順序可以是A->B->C或者B->A->C執(zhí)行最終結(jié)果都是3.14,即A和B之間沒有數(shù)據(jù)依賴性。
因?yàn)锳 happens-before B,所以A操作產(chǎn)生的結(jié)果leng一定要對B操作可見,但是現(xiàn)在B操作并沒有用到length,所以這兩個(gè)操作可以重排序,那A操作是否可以和C操作重排序呢,如果A操作和C操作進(jìn)行了重排序,因?yàn)閘eng沒有被賦值,所以leng=0,area=0*wid也就是area=0;這個(gè)結(jié)果顯然是錯(cuò)誤的,所以A操作是不能和C操作進(jìn)行重排序的(這就是注2中說的前一個(gè)操作的執(zhí)行結(jié)果必須對后羿操作可見,如果不滿足這個(gè)要求就不允許這兩個(gè)操作進(jìn)行重排序)
JMM可以通過happens-before關(guān)系提供跨線程的內(nèi)存可見性保證(如果A線程的寫操作a與B線程的讀操作b之間存在happens-before關(guān)系,盡管a操作和b操作在不同的線程中執(zhí)行,但JMM向程序員保證a操作將對b操作可見)。
1)如果一個(gè)操作happens-before另一個(gè)操作,那么第一個(gè)操作的執(zhí)行結(jié)果將對第二個(gè)操作可見,而且第一個(gè)操作的執(zhí)行順序排在第二個(gè)操作之前。
2)兩個(gè)操作之間存在happens-before關(guān)系,并不意味著Java平臺的具體實(shí)現(xiàn)必須要按照happens-before關(guān)系指定的順序來執(zhí)行。如果重排序之后的執(zhí)行結(jié)果,與按happens-before關(guān)系來執(zhí)行的結(jié)果一致,那么這種重排序并不非法(JMM允許這種重排序)。
(1) 程序順序規(guī)則:線程中每個(gè)操作,happens-before該線程任意后續(xù)操作。
(2) 監(jiān)視器鎖規(guī)則:對鎖的解鎖,happens-before于隨后對這個(gè)鎖的加鎖。
(3) volatile變量規(guī)則:對volatile域的寫,happens-before于任意后續(xù)對這個(gè)volatile域的讀/寫。
// 對一個(gè)volatile變量的寫操作happen-before對此變量的任意操作: volatile int a; a = 1; //1 b = a; //2 //如果線程1 執(zhí)行1,“線程2”執(zhí)行了2,并且“線程1”執(zhí)行后,“線程2”再執(zhí)行,那么符合“volatile的 //happen-before原則”所以“線程2”中的a值一定是1。
(4) 傳遞性:如果A happens-before B,且B happens-before C,那么A happens-before C。
(5) start()規(guī)則:如果線程A執(zhí)行操作ThreadB.start()(啟動線程B),那么A線程的 ThreadB.start()操作happens-before于線程B中的任意操作。
(6) Join()規(guī)則:如果線程A執(zhí)行操作ThreadB.join()并成功返回,那么線程B中的任意操作happens-before于線程A從**ThreadB.join()**操作成功返回。
(7) 程序中斷規(guī)則:對線程interrupted()方法的調(diào)用先行于被中斷線程的代碼檢測到中斷時(shí)間的發(fā)生。
(8) 對象finalize規(guī)則:一個(gè)對象的初始化完成(構(gòu)造函數(shù)執(zhí)行結(jié)束)先行于發(fā)生它的finalize()方法的開始。
利用程序順序規(guī)則(規(guī)則1)存在三個(gè)happens-before關(guān)系:
A happens-before B
B happens-before C
A happens-before C
這里的第三個(gè)關(guān)系是利用傳遞性進(jìn)行推論的。這里的第三個(gè)關(guān)系是利用傳遞性進(jìn)行推論的。
volatile int var; int b; int c; b = 4; //1 var = 3; //2 c = var; //3 c = b; //4
假設(shè)“線程1”執(zhí)行//1 //2這段代碼,“線程2”執(zhí)行//3 //4這段代碼。如果某次的執(zhí)行順序如下:
//1 //2 //3 //4。那么有如下推導(dǎo)( hd(a,b)表示a happen-before b):
因?yàn)橛衕d(//1,//2) 、hd(//3,//4) (單線程的happen-before原則)
且hd(//2,//3) (volatile的happen-before原則)
所以有 hd(//1,//3),可導(dǎo)出hd(//1,//4) (happen-before原則的傳遞性)
所以變量c的值最后為4 如果某次的執(zhí)行順序如下:
//1 //3 //2// //4 那么最后4的結(jié)果就不能確定嘍。其原因是 //3 //2 直接符合上述八大原則中的任何一個(gè),不能通過傳遞性推測出來什么。
A happens-before B,定義1要求A執(zhí)行結(jié)果對B可見,并且A操作的執(zhí)行順序在B操作之前,但與此同時(shí)利用定義中的第二條,A,B操作彼此不存在數(shù)據(jù)依賴性,兩個(gè)操作的執(zhí)行順序?qū)ψ罱K結(jié)果都不會產(chǎn)生影響,在不改變最終結(jié)果的前提下,允許A,B兩個(gè)操作重排序,即happens-before關(guān)系并不代表了最終的執(zhí)行順序。
不管怎么重排序(編譯器和處理器為了提高并行度),單線程程序的執(zhí)行結(jié)果不能被改變。編譯器,runtime 和處理器都必須遵守as-if-serial語義。
為了遵守as-if-serial語義,編譯器和處理器不會對存在數(shù)據(jù)依賴關(guān)系的操作做重排序,因?yàn)檫@種重排序會改變執(zhí)行結(jié)果。但是,如果操作之間不存在數(shù)據(jù)依賴關(guān)系,這些操作可能被編譯器和處理器重排序。
到此,關(guān)于“Happens-Before原則和As-If-Serial語義是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
網(wǎng)頁題目:Happens-Before原則和As-If-Serial語義是什么
轉(zhuǎn)載源于:http://aaarwkj.com/article44/peedee.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營銷、網(wǎng)站設(shè)計(jì)、網(wǎng)站設(shè)計(jì)公司、外貿(mào)網(wǎng)站建設(shè)、建站公司、網(wǎng)站策劃
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)