黄色网址大全免费-黄色网址你懂得-黄色网址你懂的-黄色网址有那些-免费超爽视频-免费大片黄国产在线观看

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動(dòng)力節(jié)點(diǎn)LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 學(xué)習(xí)攻略 Java中volatile關(guān)鍵字總結(jié)

Java中volatile關(guān)鍵字總結(jié)

更新時(shí)間:2020-06-08 16:36:59 來源:動(dòng)力節(jié)點(diǎn) 瀏覽2353次

1.什么是volatile

volatile是Java的一個(gè)關(guān)鍵字,它提供了一種輕量級(jí)的同步機(jī)制。相比于重量級(jí)鎖synchronized,volatile更為輕量級(jí),因?yàn)樗粫?huì)引起線程上下文的切換和調(diào)度。

2. volatile的兩個(gè)作用

可以禁止指令的重排序優(yōu)化

提供多線程訪問共享變量的內(nèi)存可見性

3.禁止指令重排

(1)什么是指令重排

指令重排序是JVM為了優(yōu)化指令,提高程序運(yùn)行效率,在不影響單線程程序執(zhí)行結(jié)果的前提下,盡可能地提高并行度,例如將多條指令并行執(zhí)行或者是調(diào)整指令的執(zhí)行順序。但是在多線程的情況下,指令重排序可能會(huì)帶來問題,例如程序執(zhí)行的順序可能會(huì)被調(diào)整。在加上volatile關(guān)鍵字之后可以有效解決這個(gè)問題。

下面我們舉個(gè)例子:

double r=2.1;//(1)
double pi=3.14;//(2)
double area=pi*r*r;//(3)

在代碼語句的順序?yàn)?->2->3,但實(shí)際上順序無論是1->2->3還是2->1->3對(duì)結(jié)果并無影響,所以在編譯時(shí)和運(yùn)行時(shí)可以根據(jù)需要對(duì)1、2語句進(jìn)行重排序。

重排序是指編譯器和處理器為了優(yōu)化程序性能而對(duì)指令序列進(jìn)行排序的一種手段。重排序需要遵守一定規(guī)則:

①不會(huì)對(duì)存在數(shù)據(jù)依賴關(guān)系的操作進(jìn)行重排序

②重排序是為了優(yōu)化性能,但是不管怎么重排序,單線程下程序的執(zhí)行結(jié)果不能被改變

(2)指令重排帶來的問題

我們來看看這個(gè)基于雙重檢驗(yàn)的單例模式:

public class Singleton3{
private static Singleton3 instance=null;
private Singleton3(){}
public static Singleton3 getInstance(){
if(instance==null){
synchronized(Singleton3.class){
if(instance==null)
instance=new Singleton3();//非原子操作
}
}

return instance;
}
}

事實(shí)上,這個(gè)單例模式的實(shí)現(xiàn)方式是有問題的,問題在哪呢?問題在于instance=new Singleton3();并不是一個(gè)原子操作。

我們可以將其抽象成以下幾條指令:

memory=allocate();//1:分配對(duì)象的內(nèi)存空間

ctorInstance(memory);//2:初始化對(duì)象

instance=memory;//3:設(shè)置instance指向剛分配的內(nèi)存地址

可以看到,操作2依賴于操作1,但操作3并不依賴于操作2。所以JVM是可以針對(duì)它們進(jìn)行指令的優(yōu)化重排序的,經(jīng)過重排序后如下:

memory=allocate();//1:分配對(duì)象的內(nèi)存空間

instance=memory;//3:instance指向剛分配的內(nèi)存地址,此時(shí)對(duì)象還未初始化

ctorInstance(memory);//2:初始化對(duì)象

指令重排之后,instance指向分配好的內(nèi)存放在了前面,而這段內(nèi)存的初始化被排在了后面。在線程A執(zhí)行這段賦值語句,在初始化分配對(duì)象之前就已經(jīng)將其賦值給instance引用,恰好另一個(gè)線程進(jìn)入方法判斷instance引用不為null,然后就將其返回使用,導(dǎo)致出錯(cuò)。

(3)禁止指令重排的原理

volatile關(guān)鍵字提供內(nèi)存屏障的方式來防止指令被重排,編譯器在生成字節(jié)碼文件時(shí),會(huì)在指令序列中插入內(nèi)存屏障來禁止特定類型的處理器重排序。

內(nèi)存屏障會(huì)確保指令重排序時(shí)不會(huì)把其后面的指令排到內(nèi)存屏障之前的位置,也不會(huì)把前面的指令排到內(nèi)存屏障的后面;即在執(zhí)行到內(nèi)存屏障這句指令時(shí),在它前面的操作已經(jīng)全部完成。

對(duì)于上面的基于雙重檢驗(yàn)的單例模式,我們只需對(duì)其稍作修改即可令其正確運(yùn)行。我們已經(jīng)知道,問題來自于指令重排,那么我們禁止指令重排即可,用volatile關(guān)鍵字修飾instance變量,使得instance在讀、寫操作前后都會(huì)插入內(nèi)存屏障,避免重排序。完整代碼如下:

public class Singleton3{
private static volatile Singleton3 instance=null;
private Singleton3(){}
public static Singleton3 getInstance(){
if(instance==null){
synchronized(Singleton3.class){
if(instance==null)
instance=new Singleton3();
}
}
return instance;
}
}

4.保證內(nèi)存可見性

(1)什么是保證內(nèi)存可見性

Java支持多個(gè)線程同時(shí)訪問一個(gè)對(duì)象或者對(duì)象的成員變量,由于每個(gè)線程可以擁有這個(gè)變量的拷貝(雖然對(duì)象以及成員變量分配的內(nèi)存是在共享內(nèi)存中的,但是每個(gè)執(zhí)行的線程還是可以擁有一份拷貝,這樣做的目的是加速程序的執(zhí)行,這是現(xiàn)代多核處理器的一個(gè)顯著特性),所以程序在執(zhí)行過程中,一個(gè)線程看到的變量并不一定是最新的。volatile告知程序任何對(duì)該變量的訪問均需要從共享內(nèi)存中獲取,而對(duì)它的改變必須同步刷新回共享內(nèi)存,它能保證所有線程對(duì)變量訪問的可見性。

(2)實(shí)現(xiàn)的具體細(xì)節(jié)

如果對(duì)聲明了volatile的變量進(jìn)行寫操作,JVM就會(huì)向處理器發(fā)送一條Lock前綴的指令,將這個(gè)變量所在緩存行的數(shù)據(jù)寫回到系統(tǒng)內(nèi)存。

但是,就算寫回到內(nèi)存,如果其他處理器緩存的值還是舊的,再執(zhí)行計(jì)算操作就會(huì)有問題。所以,在多處理器下,為了保證各個(gè)處理器的緩存是一致的,就會(huì)實(shí)現(xiàn)緩存一致性協(xié)議,每個(gè)處理器通過嗅探在總線上傳播的數(shù)據(jù)來檢查自己緩存的值是不是過期了,當(dāng)處理器發(fā)現(xiàn)自己緩存行對(duì)應(yīng)的內(nèi)存地址被修改,就會(huì)將當(dāng)前處理器的緩存行設(shè)置成無效狀態(tài),當(dāng)處理器對(duì)這個(gè)數(shù)據(jù)進(jìn)行修改操作的時(shí)候,會(huì)重新從系統(tǒng)內(nèi)存中把數(shù)據(jù)讀到處理器緩存里。

具體的說,內(nèi)存可見性也是通過內(nèi)存屏障實(shí)現(xiàn)的,它會(huì)執(zhí)行下面兩個(gè)操作:

強(qiáng)制將對(duì)緩存的修改操作立即寫入主存

如果是寫操作,它會(huì)導(dǎo)致其他CPU中對(duì)應(yīng)的緩存行無效

5總結(jié)

volatile提供了一種輕量級(jí)的同步機(jī)制,在訪問volatile變量時(shí)不會(huì)執(zhí)行加鎖操作,因此也就不會(huì)使執(zhí)行線程阻塞

volatile只能確??梢娦?,而加鎖機(jī)制既可以確保可見性又可以確保原子性

volatile屏蔽掉了JVM中必要的代碼優(yōu)化,所以在效率上比較低

相比synchronized,雖然volatile更簡單并且開銷更低,但它的同步性較差,而且其使用也更容易出錯(cuò)

Java中volatile關(guān)鍵字總結(jié)

Java相關(guān)技術(shù)內(nèi)容

Java中Volatile關(guān)鍵字:http://www.ilovecolors.com.cn/tutorial_java_advance/1261.html

Java Volatile關(guān)鍵字使用場(chǎng)景:http://www.ilovecolors.com.cn/tutorial_java_advance/1262.html

以上就是動(dòng)力節(jié)點(diǎn)java培訓(xùn)機(jī)構(gòu)的小編針對(duì)“Java中volatile關(guān)鍵字總結(jié)”的內(nèi)容進(jìn)行的回答,希望對(duì)大家有所幫助,如有疑問,請(qǐng)?jiān)诰€咨詢,有專業(yè)老師隨時(shí)為你服務(wù)。

提交申請(qǐng)后,顧問老師會(huì)電話與您溝通安排學(xué)習(xí)

免費(fèi)課程推薦 >>
技術(shù)文檔推薦 >>
主站蜘蛛池模板: 亚洲黄色免费在线观看 | 日韩污| 99热国品| 色永久| a级国产视频 | 免费看一级黄色大片 | 成人观看网站a | xx性动漫xx无尽xx老师 | 久久毛片免费看一区二区三区 | 男女上下猛烈动态图午夜 | 免费黄色三级网站 | 1204手机在线观看免费高清 | 激情四月婷婷 | 日本免费一区二区三区在线看 | 色香蕉在线 | 亚洲香蕉伊在人在线观看9 亚洲香蕉一区二区三区在线观看 | 精品精品国产欧美在线观看 | baoyu166.永久免费视频 | 久爱精品视频在线视频 | 深爱开心激情网 | 久久人人爽人人爽人人片va | 国产高清一区二区 | 日韩美女一区二区三区 | 国产亚洲一路线二路线高质量 | 天天骑夜夜操 | 成人免费福利网站在线看 | 91久久澡人人爽人人添 | 国产精品天天干 | 成人免费观看男女羞羞视频 | 国产日日操 | 射久久久| 亚洲乱码尤物193yw在线播放 | 丝袜国产 | 在线观看黄色网页 | 国产亚洲欧美在线 | 美女下面粉嫩粉嫩冒白浆高清 | 日韩亚洲综合精品国产 | 国产精品永久免费视频观看 | 久久95| 在线观看中文字幕 | 久久99毛片免费观看不卡 |