中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中Volatile變量有什么用

發布時間:2021-10-29 13:06:44 來源:億速云 閱讀:108 作者:小新 欄目:開發技術

這篇文章將為大家詳細講解有關Java中Volatile變量有什么用,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

    Volatile關鍵字是Java提供的一種輕量級的同步機制。Java 語言包含兩種內在的同步機制:同步塊(或方法)和 volatile 變量, 相比synchronized(synchronized通常稱為重量級鎖),volatile更輕量級,因為它不會引起線程上下文的切換和調度。 但是volatile 變量的同步性較差(有時它更簡單并且開銷更低),而且其使用也更容易出錯。

    一、volatile變量的特性

    1.1、保證可見性,不保證原子性

    • 當寫一個volatile變量時,JMM會把該線程本地內存中的變量強制刷新到主內存中去;

    • 這個寫會操作會導致其他線程中的volatile變量緩存無效。

    來看一段代碼:

    public class Test {
        public static void main(String[] args) {
            WangZai wangZai = new WangZai();
            wangZai.start();
            for(; ;){
                if(wangZai.isFlag()){
                    System.out.println("hello");
                }
            }
        }
     
        static class WangZai extends Thread {
     
            private boolean flag = false;
     
            public boolean isFlag(){
                return flag;
            }
     
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                flag = true;
                System.out.println("flag = " + flag);
            }
        }
    }

    你會發現,永遠都不會輸出hello這一段代碼,按道理線程改了flag變量,主線程也能訪問到的呀?

    但是將flag變量用volatile修飾一下,就能輸出hello這段代碼

    private volatile boolean flag = false;

    每個線程操作數據的時候會把數據從主內存讀取到自己的工作內存,如果他操作了數據并且寫會了,那其他已經讀取的線程的變量副本就會失效了,需要對數據進行操作又要再次去主內存中讀取了。

    volatile保證不同線程對共享變量操作的可見性,也就是說一個線程修改了volatile修飾的變量,當修改寫回主內存時,另外一個線程立即看到最新的值。

    1.2、禁止指令重排

    重排序需要遵守一定規則:

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

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

    什么是重排序?

    為了提高性能,編譯器和處理器常常會對既定的代碼執行順序進行指令重排序。

    重排序的類型有哪些呢?

    Java中Volatile變量有什么用

    一個好的內存模型實際上會放松對處理器和編譯器規則的束縛,也就是說軟件技術和硬件技術都為同一個目標,而進行奮斗:在不改變程序執行結果的前提下,盡可能提高執行效率。

    JMM對底層盡量減少約束,使其能夠發揮自身優勢。

    因此,在執行程序時,為了提高性能,編譯器和處理器常常會對指令進行重排序。

    一般重排序可以分為如下三種:

    • 編譯器優化的重排序。編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執行順序;

    • 指令級并行的重排序。現代處理器采用了指令級并行技術來將多條指令重疊執行。如果不存在數據依賴性,處理器可以改變語句對應機器指令的執行順序;

    • 內存系統的重排序。由于處理器使用緩存和讀/寫緩沖區,這使得加載和存儲操作看上去可能是在亂序執行的。

    那 Volatile 是怎么保證不會被執行重排序的呢?

    二、內存屏障

    java編譯器會在生成指令系列時在適當的位置會插入內存屏障指令來禁止特定類型的處理器重排序。

    為了實現volatile的內存語義,JMM會限制特定類型的編譯器和處理器重排序,JMM會針對編譯器制定volatile重排序規則表:

    是否能重排序第二個操作第一個操作普通讀/寫volatile讀volatile寫普通讀/寫NOvolatile讀NONONOvolatile寫NONO

    舉例來說,第三行最后一個單元格的意思是:在程序順序中,當第一個操作為普通變量的讀或寫時,如果第二個操作為volatile寫,則編譯器不能重排序這兩個操作。

    從上表我們可以看出:

    • 當第二個操作是volatile寫時,不管第一個操作是什么,都不能重排序。這個規則確保volatile寫之前的操作不會被編譯器重排序到volatile寫之后。

    • 當第一個操作是volatile讀時,不管第二個操作是什么,都不能重排序。這個規則確保volatile讀之后的操作不會被編譯器重排序到volatile讀之前。

    • 當第一個操作是volatile寫,第二個操作是volatile讀時,不能重排序。

    需要注意的是:volatile寫是在前面和后面分別插入內存屏障,而volatile讀操作是在后面插入兩個內存屏障。

    Java中Volatile變量有什么用

    Java中Volatile變量有什么用

    從JDK5開始,提出了happens-before的概念,通過這個概念來闡述操作之間的內存可見性。

    三、happens-before

    happens-before 關系的定義:

    • 如果一個操作 happens-before 另一個操作,那么第一個操作的執行結果就會對第二個操作可見。

    • 兩個操作之間如果存在 happens-before 關系,并不意味著 Java 平臺的具體實現就必須按照 happens-before 關系指定的順序來執行。如果重排序之后的執行結果,與按照 happens-before 關系來執行的結果一直,那么 JMM 也允許這樣的重排序。

    看到這兒,你是不是覺得,這個怎么和 as-if-serial 語義一樣呢。沒錯, happens-before 關系本質上和 as-if-serial 語義是一回事。

    as-if-serial 語義保證的是單線程內重排序之后的執行結果和程序代碼本身應該出現的結果是一致的,

    happens-before 關系保證的是正確同步的多線程程序的執行結果不會被重排序改變。

    一句話來總結就是:如果操作 A happens-before 操作 B ,那么操作 A 在內存上所做的操作對操作 B 都是可見的,不管它們在不在一個線程。

    在 Java 中,對于 happens-before 關系,有以下規定:

    • 程序順序規則:一個線程中的每一個操作, happens-before 于該線程中的任意后續操作。

    • 監視器鎖規則:對一個鎖的解鎖, happens-before 于隨后對這個鎖的加鎖。

    • volatile 變量規則:對一個 volatile 域的寫, happens-before 與任意后續對這個 volatile 域的讀。

    • 傳遞性:如果 A happens-before B , 且 B happens-before C ,那么 A happens-before C。

    • start 規則:如果線程 A 執行操作 ThreadB。start() 啟動線程 B ,那么 A 線程的 ThreadB。start() 操作 happens-before 于線程 B 中的任意操作。

    • join 規則:如果線程 A 執行操作 ThreadB。join() 并成功返回,那么線程 B 中的任意操作 happens-before 于線程 A 從 ThreadB。join() 操作成功返回。

    關于“Java中Volatile變量有什么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    原平市| 高雄县| 策勒县| 承德县| 阿拉善盟| 江门市| 西平县| 祁门县| 滦平县| 增城市| 鄂伦春自治旗| 萨嘎县| 翁源县| 新和县| 苏尼特左旗| 柳林县| 潜江市| 曲水县| 乃东县| 乌什县| 石河子市| 阳城县| 从化市| 当阳市| 商城县| 栾川县| 海丰县| 铜梁县| 南平市| 武乡县| 墨竹工卡县| 邵东县| 南昌市| 孟连| 谷城县| 静宁县| 德保县| 五指山市| 红河县| 新安县| 中卫市|