日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

vilatile 深入理解java虚拟机_《深入理解Java虚拟机》笔记 第十二章 volatile变量

發(fā)布時間:2024/10/12 java 82 豆豆
生活随笔 收集整理的這篇文章主要介紹了 vilatile 深入理解java虚拟机_《深入理解Java虚拟机》笔记 第十二章 volatile变量 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

當(dāng)一個變量定義成volatile之后,它將具備兩種特性:

1、第一是保證此變量對所有線程的可見性,這里的"可見性"是指當(dāng)一條線程修改了這個變量的值,新值對于其它線程是可以立即得知的,變量值在線程間傳遞均需要通過主內(nèi)存來完成,如:線程A修改一個普通變量的值,然后向主內(nèi)存進(jìn)行回寫,另外一條線程B在線程A回寫完成了之后再從主內(nèi)存進(jìn)行讀取操作,新變量的值才會對線程B可見。

2、使用volatile變量的第二個語義是禁止指令重排序優(yōu)化,變通的變量僅僅會保證在該方法的執(zhí)行過程中所有依賴賦值結(jié)果的地方能獲取到正確的結(jié)果,而不能保證變量的賦值操作的順序與程序代碼中的執(zhí)行順序一致。

因?yàn)樵谝粋€線程的方法執(zhí)行過程中無法感知到這一點(diǎn),這也就是Java內(nèi)存模型中描述的所謂的"線程內(nèi)表現(xiàn)為串行的語義"(Within-Thread As-If-Serial Sematics)。

關(guān)于volatile變量的可見性,很多人誤以為以下描述成立:"volatile對所有線程是立即可見的,對volatile變量所有的寫操作都能立即返回到其它線程之中,換句話說,volatile變量在各個線程中是一致的,所以基于volatile變量的運(yùn)算在并發(fā)下是安全的"。

這句話的論據(jù)部分并沒有錯,但是其論據(jù)并不能得出"基于volatile變量的運(yùn)算在并發(fā)下是安全的"這個結(jié)論。

volatile變量在各個線程的工作內(nèi)存中不存在一致性問題(在各個線程的工作內(nèi)存中volatile變量也可以存在不一致的情況,但由于每次使用之前都要先刷新,執(zhí)行引擎看不到不致的情況,因此可以認(rèn)為不存在一致性問題),但是Java里的運(yùn)算并非原子操作,導(dǎo)致volatile變量的運(yùn)算在并發(fā)下一樣是不安全的。

由于volatile變量只能保證可見性,在不符合以下條件規(guī)則的去處場景中,仍然需要通過加鎖來保證原子性。

1.運(yùn)算結(jié)果不依賴變量的當(dāng)前值,或者能確保只有單一的線程改變變量的值。

2.變量不需要與其它的狀態(tài)變量共同參與不變約束。

為何指令重排會干擾程序的并發(fā)執(zhí)行

例子

Map configOptions;

char[] configText;

//此變量必須定義為volatile

volatile boolean initialized = false;

//假設(shè)以下代碼在線程A中執(zhí)行

//模擬讀取配置信息,當(dāng)讀取完成后

//將initialized設(shè)置為true來通知其它線程配置可用

configOptions = new HashMap();

configText = readConfigFile(fileName);

processConfigOptions(configText, configOptions);

initialized = true;

//假設(shè)以下代碼在線程B中執(zhí)行

//等線程A待initialized為true,代表線程A已經(jīng)把配置信息初始化完成

while(!initialized) {

sleep();

}

//使用線程A中初始化好的配置信息

doSomethingWithConfig();

上面為一段偽代碼,其中描述的場景十分常見,只是我們在處理配置文件時一般不會出現(xiàn)并發(fā)而已。如果定義initialized變量時沒有使用volatile修飾,就可能會由于指令重排序的優(yōu)化,導(dǎo)致位于線程A中最后一句的代碼"initialized = true"被提前執(zhí)行,這樣在線程B中使用配置信息的代碼就可能出現(xiàn)錯誤,而volatile關(guān)鍵字則可以避免此類情況的發(fā)生。

Java內(nèi)存模型中對volatile變量定義的特殊規(guī)則。假定T表示一個線程,V和W分別表示兩個volatile變量,那么在進(jìn)行read、load、use、assign、store、write操作時需要滿足如下的規(guī)則:

1.只有當(dāng)線程T對變量V執(zhí)行的前一個動作是load的時候,線程T才能對變量V執(zhí)行use動作;并且,只有當(dāng)線程T對變量V執(zhí)行的后一個動作是use的時候,線程T才能對變量V執(zhí)行l(wèi)oad操作。線程T對變量V的use操作可以認(rèn)為是與線程T對變量V的load和read操作相關(guān)聯(lián)的,必須一起連續(xù)出現(xiàn)。這條規(guī)則要求在工作內(nèi)存中,每次使用變量V之前都必須先從主內(nèi)存刷新最新值,用于保證能看到其它線程對變量V所作的修改后的值。

2.只有當(dāng)線程T對變量V執(zhí)行的前一個動是assign的時候,線程T才能對變量V執(zhí)行store操作;并且,只有當(dāng)線程T對變量V執(zhí)行的后一個動作是store操作的時候,線程T才能對變量V執(zhí)行assign操作。線程T對變量V的assign操作可以認(rèn)為是與線程T對變量V的store和write操作相關(guān)聯(lián)的,必須一起連續(xù)出現(xiàn)。這一條規(guī)則要求在工作內(nèi)存中,每次修改V后都必須立即同步回主內(nèi)存中,用于保證其它線程可以看到自己對變量V的修改。

3.假定操作A是線程T對變量V實(shí)施的use或assign動作,假定操作F是操作A相關(guān)聯(lián)的load或store操作,假定操作P是與操作F相應(yīng)的對變量V的read或write操作;類型地,假定動作B是線程T對變量W實(shí)施的use或assign動作,假定操作G是操作B相關(guān)聯(lián)的load或store操作,假定操作Q是與操作G相應(yīng)的對變量V的read或write操作。如果A先于B,那么P先于Q。這條規(guī)則要求valitile修改的變量不會被指令重排序優(yōu)化,保證代碼的執(zhí)行順序與程序的順序相同。

總結(jié)

以上是生活随笔為你收集整理的vilatile 深入理解java虚拟机_《深入理解Java虚拟机》笔记 第十二章 volatile变量的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。