2022-03-20

volatile

volatile關(guān)鍵字在Java面試中幾乎是必考題
單例模式的雙重檢查模式(DCL)一般會(huì)引申到synchronized關(guān)鍵字和volatile關(guān)鍵字

volatile關(guān)鍵字了解嗎?它保證了什么特性?用什么方式禁止指令重排的嗎?

1)volatile保證了什么特性

  • 保證線程可見性(多線程環(huán)境下保證內(nèi)存可見性)

    • 線程修改后的共享變量值能夠及時(shí)刷新,從工作內(nèi)存中刷新回主內(nèi)存;
    • 其它線程能夠及時(shí)的把共享變量的值從主內(nèi)存中更新到自己的工作內(nèi)存中;
    • Java 內(nèi)存模型規(guī)定,對(duì)于多個(gè)線程共享的變量,存儲(chǔ)在主內(nèi)存當(dāng)中,每個(gè)線程都有自己獨(dú)立的工作內(nèi)存,并且線程只能訪問自己的工作內(nèi)存,不可以訪問其它線程的工作內(nèi)存。工作內(nèi)存中保存了主內(nèi)存中共享變量的副本,線程要操作這些共享變量,只能通過操作工作內(nèi)存中的副本來實(shí)現(xiàn),操作完畢之后再同步回到主內(nèi)存當(dāng)中,其 JVM 模型大致如下圖。
    • image-20210511121557443
  • 禁止指令重排序優(yōu)化(多線程模式下禁止指令重排序優(yōu)化)

    • 哪條代碼需要指令重排?

      instance = new instance();

    • 使用了volatile關(guān)鍵字之后,重排序被禁止,所有的寫操作(write)都發(fā)生在讀操作(read)之前。

用什么方式禁止指令重排的嗎?

內(nèi)存屏障:

  1. 讀屏障(Load Barrier):在讀指令前插入Load Barrier,可以讓高速緩存中的數(shù)據(jù)失效,強(qiáng)制重新從主內(nèi)存加載數(shù)據(jù),保證讀取的是最新數(shù)據(jù)。

  2. 寫屏障(Store Barrier):在寫指令后插入Store Barrier,能讓寫入緩存中的最新數(shù)據(jù)更新寫入主內(nèi)存,保證寫入的數(shù)據(jù)立刻對(duì)其他線程可見。

  • 在工作內(nèi)存中,每次使用V(volatile變量)前都必須先從主內(nèi)存刷新最新的值,用于保證能看見其他線程對(duì)變量V所做的修改。
  • 在工作內(nèi)存中,每次修改V后都必須立刻同步回主內(nèi)存中,用于保證其他線程可以看到自己對(duì)變量V所做的修改。

2)volatile導(dǎo)致哪條代碼需要指令重排?

instance = new Singleton();  

會(huì)被編譯器編譯成如下JVM指令:

  1. memory = allocate(); //分配對(duì)象的內(nèi)存空間
  2. ctorInstance(memory); //初始化對(duì)象
  3. instance = memory; //設(shè)置instance指向剛分配的內(nèi)存空間

但是這些指令排序并非一成不變,有可能會(huì)經(jīng)過JVM和CPU的優(yōu)化,指令重排為如下順序:

  1. memory = allocate(); //分配對(duì)象的內(nèi)存空間
  2. instance = memory; //設(shè)置instance指向剛分配的內(nèi)存空間
  3. ctorInstance(memory); //初始化對(duì)象

當(dāng)線程A執(zhí)行完1,3,時(shí),instance對(duì)象還未完成初始化,但已經(jīng)不再指向null。此時(shí)如果線程B搶占到CPU資源,執(zhí)行 if(instance == null)的結(jié)果會(huì)是false,從而返回一個(gè)沒有初始化完成的instance對(duì)象。

實(shí)例化對(duì)象實(shí)際會(huì)分為3個(gè)步驟:

  1. 分配內(nèi)存空間
  2. 初始化對(duì)象
  3. 將對(duì)象指向剛分配的內(nèi)存空間

但有的編譯器由于性能的原因,可能會(huì)將第二步和第三步進(jìn)行重排序,順序就成了:

  1. 分配內(nèi)存空間
  2. 將對(duì)象指向剛分配的內(nèi)存空間
  3. 初始化對(duì)象
image-20210505162555490.png

使用了volatile關(guān)鍵字之后,重排序被禁止,所有的寫操作(write)都發(fā)生在讀操作(read)之前。

?著作權(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)容