日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
JMM指令重排序的示例分析

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

成都創(chuàng)新互聯(lián)10多年成都企業(yè)網(wǎng)站建設服務;為您提供網(wǎng)站建設,網(wǎng)站制作,網(wǎng)頁設計及高端網(wǎng)站定制服務,成都企業(yè)網(wǎng)站建設及推廣,對成都宣傳片制作等多個行業(yè)擁有多年的營銷推廣經(jīng)驗的網(wǎng)站建設公司。

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

在計算機系統(tǒng)中,指令為了更快的完成結(jié)果,會根據(jù)邏輯關(guān)系、指令大小進行重排序,以達到超流水線的效果,但在代碼執(zhí)行完后,保證結(jié)果輸出是一致的。

在JVM中又兩條原則:

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

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

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

我們知道,JIT會根據(jù)CPU架構(gòu)編譯合適的代碼去執(zhí)行,因此,在匯編層面討論反而不見得能統(tǒng)一意見,比如X86,他只有l(wèi)ock來實現(xiàn),其他CPU架構(gòu)則是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可能重排序后的結(jié)果,實際上寄存器、CPU也會進行重排序,但最終也會保證內(nèi)存一致性。

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

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

3 .1  要不要禁止

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

3.2 原理

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

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

讀操作

JMM指令重排序的示例分析

寫操作

JMM指令重排序的示例分析

3.3 效果演示

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

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);
    }
}

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

四、final和volatile的區(qū)別?

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

不同點:

final字段的寫操作,只作用于構(gòu)造函數(shù)。

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

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


分享名稱:JMM指令重排序的示例分析
URL標題:http://www.dlmjj.cn/article/pgghgc.html