老熟女激烈的高潮_日韩一级黄色录像_亚洲1区2区3区视频_精品少妇一区二区三区在线播放_国产欧美日产久久_午夜福利精品导航凹凸

關于Java關鍵字volatile的總結

1 什么是 volatile

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

公司主營業務:成都做網站、成都網站設計、移動網站開發等業務。幫助企業客戶真正實現互聯網宣傳,提高企業的競爭能力。創新互聯是一支青春激揚、勤奮敬業、活力青春激揚、勤奮敬業、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴謹、自律”為核心的企業文化,感謝他們對我們的高要求,感謝他們從不同領域給我們帶來的挑戰,讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。創新互聯推出興隆免費做網站回饋大家。

2 volatile 的兩個作用

  1. 可以禁止指令的重排序優化
  2. 提供多線程訪問共享變量的內存可見性

3 禁止指令重排

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語句進行重排序。

重排序是指編譯器和處理器為了優化程序性能而對指令序列進行排序的一種手段。重排序需要遵守一定規則:
1 不會對存在數據依賴關系的操作進行重排序
2 重排序是為了優化性能,但是不管怎么重排序,單線程下程序的執行結果不能被改變

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

4.1 什么是保證內存可見性

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

4.2 實現的具體細節

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

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

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

  1. 強制將對緩存的修改操作立即寫入主存
  2. 如果是寫操作,它會導致其他 CPU 中對應的緩存行無效

5 總結

  1. volatile 提供了一種輕量級的同步機制,在訪問 volatile 變量時不會執行加鎖操作,因此也就不會使執行線程阻塞
  2. volatile 只能確保可見性,而加鎖機制既可以確保可見性又可以確保原子性
  3. volatile 屏蔽掉了 JVM 中必要的代碼優化,所以在效率上比較低
  4. 相比 synchronized,雖然 volatile 更簡單并且開銷更低,但它的同步性較差,而且其使用也更容易出錯

分享文章:關于Java關鍵字volatile的總結
本文來源:http://www.xueling.net.cn/article/ggphhj.html

其他資訊

在線咨詢
服務熱線
服務熱線:028-86922220
TOP
主站蜘蛛池模板: 丰满白嫩的大屁股哺乳期偷吃少妇 | 亚洲AV无码成人精品区蜜桃 | 亚洲一及片| 老师开裆丝袜喷水视频 | 日日摸日日碰夜夜爽视频 | 亚洲欧美国产中文 | 人人爽人人爽av | 国产九九热| 亚洲成a∧人片在线播放 | 久久久久欠精品国产毛片国产毛生 | 亚洲精品国产九九九 | 国产美女操b在线观看 | 久草热视频 | 内射爽无广熟女亚洲 | 日本三级在线观看视频 | 亚洲精品无码精品MV在线观看 | 精品一区二区三区影院在线午夜 | 亚洲国产中文字幕在线 | 欧美多毛肥胖老妇做爰 | 夜夜操人人 | 黄色一级免费观看 | 最近中文字幕高清中文字幕无 | 亚洲国产精品欧美久久 | 欧美大陆国产 | 亚洲综合色区另类av | 免费看成年人视频在线观看 | 日本精品一区 | 四虎在线永久免费观看 | 91日韩久久 | 成人影院欧美黄色 | 精品日产一区二区三区视频怎么看 | 国产精品中文 | 欧美精品在线观看 | 乱人伦人妻中文字幕无码久久网 | 国产美女自慰在线观看 | 国产日韩精品一区二区三区在线 | 伊人情人色综合网站 | 国产亚洲精品久久久久久网站 | www国产亚洲 | 黄色网站免费观看视频 | 无遮挡国产高潮视频免费观看 |