大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動力節點LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 學習攻略 Java中volatile關鍵字總結

Java中volatile關鍵字總結

更新時間:2020-06-08 16:36:59 來源:動力節點 瀏覽2266次

1.什么是volatile

volatile是Java的一個關鍵字,它提供了一種輕量級的同步機制。相比于重量級鎖synchronized,volatile更為輕量級,因為它不會引起線程上下文的切換和調度。

2. volatile的兩個作用

可以禁止指令的重排序優化

提供多線程訪問共享變量的內存可見性

3.禁止指令重排

(1)什么是指令重排

指令重排序是JVM為了優化指令,提高程序運行效率,在不影響單線程程序執行結果的前提下,盡可能地提高并行度,例如將多條指令并行執行或者是調整指令的執行順序。但是在多線程的情況下,指令重排序可能會帶來問題,例如程序執行的順序可能會被調整。在加上volatile關鍵字之后可以有效解決這個問題。

下面我們舉個例子:

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

在代碼語句的順序為1->2->3,但實際上順序無論是1->2->3還是2->1->3對結果并無影響,所以在編譯時和運行時可以根據需要對1、2語句進行重排序。

重排序是指編譯器和處理器為了優化程序性能而對指令序列進行排序的一種手段。重排序需要遵守一定規則:

①不會對存在數據依賴關系的操作進行重排序

②重排序是為了優化性能,但是不管怎么重排序,單線程下程序的執行結果不能被改變

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

我們來看看這個基于雙重檢驗的單例模式:

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;
}
}

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

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

memory=allocate();//1:分配對象的內存空間

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

instance=memory;//3:設置instance指向剛分配的內存地址

可以看到,操作2依賴于操作1,但操作3并不依賴于操作2。所以JVM是可以針對它們進行指令的優化重排序的,經過重排序后如下:

memory=allocate();//1:分配對象的內存空間

instance=memory;//3:instance指向剛分配的內存地址,此時對象還未初始化

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

指令重排之后,instance指向分配好的內存放在了前面,而這段內存的初始化被排在了后面。在線程A執行這段賦值語句,在初始化分配對象之前就已經將其賦值給instance引用,恰好另一個線程進入方法判斷instance引用不為null,然后就將其返回使用,導致出錯。

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

volatile關鍵字提供內存屏障的方式來防止指令被重排,編譯器在生成字節碼文件時,會在指令序列中插入內存屏障來禁止特定類型的處理器重排序。

內存屏障會確保指令重排序時不會把其后面的指令排到內存屏障之前的位置,也不會把前面的指令排到內存屏障的后面;即在執行到內存屏障這句指令時,在它前面的操作已經全部完成。

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

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.保證內存可見性

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

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

(2)實現的具體細節

如果對聲明了volatile的變量進行寫操作,JVM就會向處理器發送一條Lock前綴的指令,將這個變量所在緩存行的數據寫回到系統內存。

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

具體的說,內存可見性也是通過內存屏障實現的,它會執行下面兩個操作:

強制將對緩存的修改操作立即寫入主存

如果是寫操作,它會導致其他CPU中對應的緩存行無效

5總結

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

volatile只能確保可見性,而加鎖機制既可以確保可見性又可以確保原子性

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

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

Java中volatile關鍵字總結

Java相關技術內容

Java中Volatile關鍵字:http://www.dabaquan.cn/tutorial_java_advance/1261.html

Java Volatile關鍵字使用場景:http://www.dabaquan.cn/tutorial_java_advance/1262.html

以上就是動力節點java培訓機構的小編針對“Java中volatile關鍵字總結”的內容進行的回答,希望對大家有所幫助,如有疑問,請在線咨詢,有專業老師隨時為你服務。

提交申請后,顧問老師會電話與您溝通安排學習

免費課程推薦 >>
技術文檔推薦 >>
主站蜘蛛池模板: 欧美一级成人毛片影院 | 狠狠综合欧美综合欧美色 | 91精品国产免费自在线观看 | 波多野结衣中文字幕一区二区 | 亚洲国产精品xo在线观看 | 99热成人精品国产免男男 | 天天都色| 国内精品伊人久久久影视 | 久草免费在线视频 | 手机看片日韩日韩国产在线看 | 中文字幕专区 | 国产精品视频ccav | 亚洲成人第一页 | 国产伦乱 | 色偷偷91久久综合噜噜噜噜 | 在线免费看a | 午夜精品久久久久久久90蜜桃 | 亚洲毛片一级带毛片基地 | 一区二区三区日韩 | 性感美女香蕉视频 | 欧美一级午夜免费视频你懂的 | 四虎精品永久在线 | 欧洲一级黄色 | 午夜国产在线观看 | 久久久亚洲伊人色综合网站 | 亚洲精品区 | 四虎国产精品永久地址99 | www.精东| 欧美爱爱视频网站 | 视频一区二区三区在线观看 | 成人短视频在线观看免费 | 四虎视频国产精品免费入口 | 俄罗斯毛片视频 | 老子影院午夜伦手机不四虎 | www性欧美| 欧美成人免费在线视频 | 日韩欧美高清视频 | 久久精品国产精品亚洲综合 | 中文国产成人精品久久一 | 在线视频 中文字幕 | 成年人黄色小视频 |