欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java多線程并發(fā)編程 Volatile關(guān)鍵字

 更新時(shí)間:2017年05月22日 23:23:50   投稿:mdxy-dxy  
volatile 關(guān)鍵字是一個(gè)神秘的關(guān)鍵字,也許在 J2EE 上的 JAVA 程序員會(huì)了解多一點(diǎn),但在 Android 上的 JAVA 程序員大多不了解這個(gè)關(guān)鍵字。只要稍了解不當(dāng)就好容易導(dǎo)致一些并發(fā)上的錯(cuò)誤發(fā)生,例如好多人把 volatile 理解成變量的鎖

volatile 關(guān)鍵字是一個(gè)神秘的關(guān)鍵字,也許在 J2EE 上的 JAVA 程序員會(huì)了解多一點(diǎn),但在 Android 上的 JAVA 程序員大多不了解這個(gè)關(guān)鍵字。只要稍了解不當(dāng)就好容易導(dǎo)致一些并發(fā)上的錯(cuò)誤發(fā)生,例如好多人把 volatile 理解成變量的鎖。(并不是)

volatile 的特性:

具備可見(jiàn)性

保證不同線程對(duì)被 volatile 修飾的變量的可見(jiàn)性。

有一被 volatile 修飾的變量 i,在一個(gè)線程中修改了此變量 i,對(duì)于其他線程來(lái)說(shuō) i 的修改是立即可見(jiàn)的。

如:

volatile int i = 0;// 語(yǔ)句 1
i++; // 語(yǔ)句 2

語(yǔ)句 2 執(zhí)行完后,i 最新的值會(huì)立即被強(qiáng)制更新到主內(nèi)存(共享內(nèi)存),并通知其他緩存了 i 的線程,令其他線程的工作內(nèi)存里的 i 失效,從而需重新到主內(nèi)存讀取最新的值。

具備有序性

被 volatile 修飾的變量,不會(huì)被優(yōu)化排序。

解決的問(wèn)題詳見(jiàn):Java 多線程并發(fā)編程 并發(fā)三大要素 的 三、有序性。

當(dāng)編譯器在給程序優(yōu)化排序時(shí),若遇到 volatile 變量的讀操作或者寫(xiě)操作,則會(huì)保證在其前面的操作全部進(jìn)行完成,且結(jié)果對(duì)后面的操作可見(jiàn);并且保證在其后面的操作沒(méi)有進(jìn)行。

不具備原子性

volatile 不具備原子性,所以它是線程不安全的。

實(shí)驗(yàn):

// 一個(gè)單例的實(shí)現(xiàn)
public class SingletonTest {

  private static volatile SingletonTest mInstance = null;

  private SingletonTest() {}

  public static SingletonTest getInstance() {

    if (mInstance == null) {
      mInstance = new SingletonTest();
      System.out.println(" 初始化完成 ");
    }

    return mInstance;
  }
}


// 測(cè)試代碼
public class Test {

  public static void main(String[] var0) {
    for(int i = 0; i < 20; i++){
      ThreadTest test = new ThreadTest();
      test.start();
    }
  }

  static class ThreadTest extends Thread{

    @Override
    public void run() {
      super.run();

      SingletonTest.getInstance();
    }
  }

}

結(jié)果:
每次運(yùn)行都輸出多個(gè) “初始化完成”。

volatile 的解釋

下面這段話摘自《深入理解 Java 虛擬機(jī)》:

“觀察加入 volatile 關(guān)鍵字和沒(méi)有加入 volatile 關(guān)鍵字時(shí)所生成的匯編代碼發(fā)現(xiàn),加入 volatile 關(guān)鍵字時(shí),會(huì)多出一個(gè) lock 前綴指令”

被 volatile 修飾的變量進(jìn)行讀和寫(xiě)操作的時(shí)候,在相應(yīng)的匯編程序中都會(huì)多一句內(nèi)存屏障(Memory Barrier)。

而這個(gè) lock 就是內(nèi)存屏障。

內(nèi)存屏障的作用:

1、在重新優(yōu)化排序時(shí)保證其后面的指令不會(huì)被排到內(nèi)存屏障的前面,前面的指令也不會(huì)排到內(nèi)存屏障的后面。- 有序性

2、強(qiáng)制對(duì)寫(xiě)操作后的結(jié)果(立即)刷新到主內(nèi)存。

3、刷新結(jié)果到主內(nèi)存時(shí),通知并令其他線程緩存內(nèi)的值過(guò)期 / 失效。

2 和 3 合起來(lái)則是可見(jiàn)性。

說(shuō)到這里,也許會(huì)有好多人困惑,既然可見(jiàn)性可以保證,既然可以做到修改某個(gè)變量的值后,會(huì)刷新到主內(nèi)存,并令其他線程緩存失效,為什么不能保證原子性呢?這也是我之前走進(jìn)的一個(gè)困區(qū)。

繼續(xù)用 i++ 來(lái)分析一下,這里面包含的指令:

從主內(nèi)存讀取到緩存 // 指令 1
進(jìn)行運(yùn)算 // 指令 2
從緩存刷新到主內(nèi)存 // 指令 3
內(nèi)存屏障 // 指令 4

雖然指令 4(內(nèi)存屏障)功能強(qiáng)大,但可惜 // 指令 1、2、3 都不是具備原子性,所以導(dǎo)致 volatile 不具備原子性,線程不安全,不能替代鎖的作用。

使用場(chǎng)景

如一些簡(jiǎn)單的狀態(tài)標(biāo)記:

volatile boolean inited = false;

// 線程 1
init(); // 語(yǔ)句 1
inited = true; // 語(yǔ)句 2

// 線程 2
while(inited){
	work(); // 語(yǔ)句 3
}

1、可確保語(yǔ)句 1 和語(yǔ)句 2 的執(zhí)行順序。
2、可確保執(zhí)行語(yǔ)句 2 后,線程 2 可立即獲取到最新的修改,從而執(zhí)行語(yǔ)句 3。

相關(guān)文章

  • Java數(shù)據(jù)結(jié)構(gòu)之實(shí)現(xiàn)跳表

    Java數(shù)據(jù)結(jié)構(gòu)之實(shí)現(xiàn)跳表

    今天帶大家來(lái)學(xué)習(xí)Java數(shù)據(jù)結(jié)構(gòu)的相關(guān)知識(shí),文中對(duì)用Java實(shí)現(xiàn)跳表作了非常詳細(xì)的圖文解說(shuō)及代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • 淺談servlet3異步原理與實(shí)踐

    淺談servlet3異步原理與實(shí)踐

    本篇文章主要介紹了servlet3異步原理與實(shí)踐,詳細(xì)的介紹了servlet和異步的流程使用,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-10-10
  • Springboot實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)流程詳解

    Springboot實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)流程詳解

    通過(guò)重寫(xiě)SchedulingConfigurer方法實(shí)現(xiàn)對(duì)定時(shí)任務(wù)的操作,單次執(zhí)行、停止、啟動(dòng)三個(gè)主要的基本功能,動(dòng)態(tài)的從數(shù)據(jù)庫(kù)中獲取配置的定時(shí)任務(wù)cron信息,通過(guò)反射的方式靈活定位到具體的類與方法中
    2022-09-09
  • Java 基礎(chǔ)語(yǔ)法 異常處理

    Java 基礎(chǔ)語(yǔ)法 異常處理

    這篇我們就來(lái)介紹Java 基礎(chǔ)語(yǔ)法中長(zhǎng)遇到的那些異常及處理方法的一下相關(guān)資料,感興趣的小伙伴可以參考一下下面文章的詳細(xì)內(nèi)容,希望對(duì)你有所幫助
    2021-10-10
  • 在idea中顯示springboot面板的方法

    在idea中顯示springboot面板的方法

    這篇文章主要介紹了在idea中顯示springboot面板的方法方便啟動(dòng)調(diào)試,本文通過(guò)代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • 詳解SpringMVC 自動(dòng)封裝枚舉類的方法

    詳解SpringMVC 自動(dòng)封裝枚舉類的方法

    springmvc默認(rèn)無(wú)法自動(dòng)封裝枚舉類,本篇文章主要介紹了詳解SpringMVC 自動(dòng)封裝枚舉類的方法,有興趣的可以了解一下。
    2017-04-04
  • mybatis 插件: 打印 sql 及其執(zhí)行時(shí)間實(shí)現(xiàn)方法

    mybatis 插件: 打印 sql 及其執(zhí)行時(shí)間實(shí)現(xiàn)方法

    下面小編就為大家?guī)?lái)一篇mybatis 插件: 打印 sql 及其執(zhí)行時(shí)間實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • java 中 System.out.println()和System.out.write()的區(qū)別

    java 中 System.out.println()和System.out.write()的區(qū)別

    這篇文章主要介紹了 java 中 System.out.println()和System.out.write()的區(qū)別.的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Java實(shí)現(xiàn)驗(yàn)證碼驗(yàn)證功能

    Java實(shí)現(xiàn)驗(yàn)證碼驗(yàn)證功能

    Java如何實(shí)現(xiàn)驗(yàn)證碼驗(yàn)證功能呢?日常生活中,驗(yàn)證碼隨處可見(jiàn),他可以在一定程度上保護(hù)賬號(hào)安全,那么他是怎么實(shí)現(xiàn)的呢?今天通過(guò)本文給大家實(shí)例詳解,需要的朋友參考下
    2017-02-02
  • Java異常架構(gòu)和異常關(guān)鍵字圖文詳解

    Java異常架構(gòu)和異常關(guān)鍵字圖文詳解

    Java異常是Java提供的一種識(shí)別及響應(yīng)錯(cuò)誤的一致性機(jī)制,下面這篇文章主要給大家介紹了關(guān)于Java異常架構(gòu)和異常關(guān)鍵字的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05

最新評(píng)論