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

溫馨提示×

溫馨提示×

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

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

JMM指令重排序的示例分析

發布時間:2021-09-05 18:35:40 來源:億速云 閱讀:398 作者:小新 欄目:編程語言

這篇文章給大家分享的是有關JMM指令重排序的示例分析的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

一、指令為什么要重排序?

在計算機系統中,指令為了更快的完成結果,會根據邏輯關系、指令大小進行重排序,以達到超流水線的效果,但在代碼執行完后,保證結果輸出是一致的。

在JVM中又兩條原則:

  • as-if -serials         這個規則適用于單線程,默認自動處理

  • happens-before   這個規則適用于多線程,當然也要通過相應的鎖和關鍵字來實現

二、JMM(Java Memory Manager)指令重排序如何實現的呢?

我們知道,JIT會根據CPU架構編譯合適的代碼去執行,因此,在匯編層面討論反而不見得能統一意見,比如X86,他只有lock來實現,其他CPU架構則是LoadLoad,StoreStore,LoadStore,StoreLoad

實際上我們還是在JIT層面思考比較容易理解,這里我們定義一個類

(注意:這個類未必和JIT實際效果一致,取決于JIT激進程度)

package com.apptest;

public class VolatileWatcher {

    private String A;
    private String B;
    private String C;
    private String D;
    private String E;

    public void run() {
        String a = "a";
        String b = "b";
        String c = "c";
        String d = "d";
        String e = "e";
        A = a;
        B = b;
        C = c;
        D = d;
        E = e;

        System.out.println(A);
        System.out.println(B);
        System.out.println(C);
        System.out.println(D);
        System.out.println(E);
    }
}

那么如果重排序,效果可能如下

package com.apptest;

public class VolatileWatcher {

    private String A;
    private String B;
    private String C;
    private String D;
    private String E;

 
    public void run() {
        String a = "a";
        String b = "b";
        String c = "c";
        String d = "d";
        String e = "e";

        A = a;
        System.out.println(A);

        B = b;
        System.out.println(B);

        C = c;
        System.out.println(C);
        D = d;
        System.out.println(D);

        E = e;
        System.out.println(E);
    }
}

這是JIT可能重排序后的結果,實際上寄存器、CPU也會進行重排序,但最終也會保證內存一致性。

三、如何禁止指令重排序呢?

Java中,禁止指令重排序的關鍵字只有2個,一個是volatile、另一個是final,某種成都上,也能說明final和volatile不能同時修飾一個變量的原因,因為他們的功能有些重疊。

3 .1  要不要禁止

首先要確定要不要禁止重排序,重排序往往在多線程中出現問題,如果程序在串行執行,完全沒有必要,因此,單線程中的引用類型(不包括常量和字符串常量,這些類型引用建議加final)建議不要加final和volatile,當然,final需要考慮深入一些,因為有時我們需要做一些強約束,但總體來說能不加就不加。

3.2 原理

多線程中,維護hanpens-before原則不是JVM自身就能處理的,還需要在代碼層面進行相應的指示,此外,相應的JIT會將指示編譯成指令,讓寄存器和CPU也遵守。

指令重排序的達到的最終效果

讀操作

JMM指令重排序的示例分析

寫操作

JMM指令重排序的示例分析

3.3 效果演示

回到文章開頭,我們給VolatileWatcher的C變量添加volatile修飾,那么JIT重排序后的結果可能是如下情況

public class VolatileWatcher {

    private String A;
    private String B;
    private volatile String C;
    private String D;
    private String E;

    public void run() {
        String a = "a";
        String b = "b";
        String c = "c";
        String d = "d";
        String e = "e";
        B = b;
        A = a;
        C = c; //寫屏障
        E = e;
        D = d;

        System.out.println(A);
        System.out.println(B);
        System.out.println(C); //讀屏障
        System.out.println(D);
        System.out.println(E);
    }
}

我們發現,A、B不能跨越C變量的寫屏障往下重排序,但是屏障上方的A、B之間也是可以重排序的,E、D不能跨越讀屏障,但是E、D可以在讀屏障和寫屏障之間排序。(這里故意寫成A,B,E,D在屏障外順序變化,目的主要是為了說明屏障的作用,具體看實際效果)

四、final和volatile的區別?

我們知道,final修飾的是只讀變量,有很強的“只讀”約束性,所有final修飾的變量都需要在構造方法中初始化(類外部final字段的最終會插入到super(...)之后 ),而volatile一般用于多線程變量的讀寫,但他們都具備實現內存屏障的能力,可以說,都能實現禁止重排序。

不同點:

final字段的寫操作,只作用于構造函數。

final字段的讀操作,讀取和volatile基本一樣

感謝各位的閱讀!關于“JMM指令重排序的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

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

jmm
AI

建始县| 乌审旗| 桃源县| 锡林郭勒盟| 苏尼特左旗| 社旗县| 繁峙县| 洱源县| 永康市| 普兰店市| 宝鸡市| 丰顺县| 淮安市| 永胜县| 铜陵市| 和政县| 彰武县| 宣恩县| 绥阳县| 准格尔旗| 林州市| 通城县| 德庆县| 昭平县| 涟源市| 东山县| 巴林右旗| 乌审旗| 临漳县| 武邑县| 彰武县| 深州市| 盐亭县| 连城县| 密云县| 昭觉县| 延津县| 阜康市| 祁门县| 保山市| 榆社县|