深入剖析Java關(guān)鍵字之volatile

一翘鸭、摘要

?在《JMM之happens-before詳解》這篇文章中,我們知道了happens-before規(guī)則中的有一條是volatile規(guī)則:對(duì)一個(gè)volatile域的寫戳葵,happens-before于任意后續(xù)對(duì)這個(gè)volatile域的讀就乓。那么,Java是如何實(shí)現(xiàn)這個(gè)規(guī)則的呢拱烁?本文我們將從volatile的作用生蚁,cpu的緩存結(jié)構(gòu)以及volatile實(shí)例的匯編等幾個(gè)方面來(lái)詳細(xì)解讀volatile的實(shí)現(xiàn)原理。


二戏自、volatile關(guān)鍵字的作用

?我們從一個(gè)例子來(lái)解釋volatile的作用:

import java.util.concurrent.TimeUnit;

/**
 * <Description> <br>
 *
 * @author Sunny<br>
 * @version 1.0<br>
 * @taskId: <br>
 * @createDate 2019/02/18 10:27 <br>
 * @see com.sunny.concurrent.volatilekey <br>
 */
public class VolatileFoo {
    /**
     * init_value的最大值
     */
    final static int MAX = 5;
    /**
     * init_value的初始值
     */
    static int init_value = 0;

    public static void main(String[] args)
    {
        int x = 10;
        x = x++;
        System.out.println();

        /**
         * 啟動(dòng)一個(gè)Reader線程邦投,當(dāng)發(fā)現(xiàn)local_value和init_value不同時(shí),則輸出init_value被修改的信息
         */
        new Thread(() ->
        {
            int localValue = init_value;
            while (localValue < MAX)
            {
                if (init_value != localValue)
                {
                    System.out.printf("Current thread is [%s] and the init_value is updated to [%d]\n", Thread.currentThread().getName(),init_value);
                    localValue = init_value;
                }
            }
        }, "Reader").start();

        /**
         * 啟動(dòng)一個(gè)Updater線程擅笔,主要用于對(duì)init_value的修改志衣,當(dāng)localValue >= 5 時(shí),則退出生命周期
         */
        new Thread(() ->
        {
            int localValue = init_value;
            while (localValue < MAX)
            {
                System.out.printf("Current thread is [%s] and the init_value will be changed to [%d]\n", Thread.currentThread().getName(),  ++localValue);
                init_value = localValue;
                try
                {
                    // 短暫休眠猛们,目的是為了使Reader線程能夠來(lái)得及輸出變化內(nèi)容
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }, "Updater").start();
    }
}

?輸出如下:

Current thread is [Updater] and the init_value will be changed to [1]
Current thread is [Updater] and the init_value will be changed to [2]
Current thread is [Updater] and the init_value will be changed to [3]
Current thread is [Updater] and the init_value will be changed to [4]
Current thread is [Updater] and the init_value will be changed to [5]

?上面輸出之后念脯,Reader線程進(jìn)入死循環(huán);也就是說(shuō)Reader線程沒(méi)有感知到Updater線程對(duì)init_value變量的修改弯淘;接下來(lái)我們對(duì)init_value的定義做一下小小的改動(dòng)绿店,改成如下方式:

static volatile int init_value = 0;

?將輸出如下結(jié)果:

Current thread is [Updater] and the init_value will be changed to [1]
Current thread is [Reader] and the init_value is updated to [1]
Current thread is [Updater] and the init_value will be changed to [2]
Current thread is [Reader] and the init_value is updated to [2]
Current thread is [Updater] and the init_value will be changed to [3]
Current thread is [Reader] and the init_value is updated to [3]
Current thread is [Updater] and the init_value will be changed to [4]
Current thread is [Reader] and the init_value is updated to [4]
Current thread is [Updater] and the init_value will be changed to [5]
Current thread is [Reader] and the init_value is updated to [5]

Process finished with exit code 0

?為什么會(huì)出現(xiàn)這樣的情況呢?其實(shí)都是volatile的作用庐橙,后面章節(jié)會(huì)分析其原理惯吕。注意:volatile關(guān)鍵字只能修飾類變量和實(shí)例變量惕它,對(duì)于方法參數(shù)、局部變量以及實(shí)例常量废登,類常量都不能進(jìn)行修飾淹魄,比如上面代碼中的MAX就不能使用volatile關(guān)鍵字進(jìn)行修飾。


三堡距、機(jī)器硬件CPU與緩存一致性協(xié)議

?其實(shí)在《【轉(zhuǎn)】偽共享甲锡、緩存行填充和CPU緩存詳述》 這篇文章中有簡(jiǎn)單講述CPU的三級(jí)緩存結(jié)構(gòu)。
?隨著CPU的頻率不斷地得到提升羽戒,但受制于制造工藝以及成本等的限制缤沦,計(jì)算機(jī)的內(nèi)存反倒在訪問(wèn)速度上沒(méi)有多大的突破,因此CPU的處理速度和內(nèi)存的訪問(wèn)速度之間的差距越拉越大易稠,通常這種差距可以達(dá)到上千倍缸废,極端情況下甚至上萬(wàn)倍以上。

3.1 CPU Cache模型

?由于兩邊速度的嚴(yán)重不對(duì)等驶社,通過(guò)傳統(tǒng)FSB直連內(nèi)存的訪問(wèn)方式很明顯會(huì)導(dǎo)致CPU資源受到大量的限制企量,降低CPU整體的吞吐量,于是就有了在CPU和主內(nèi)存之間增加緩存的設(shè)計(jì)亡电,現(xiàn)在的緩存數(shù)量都已經(jīng)增加到了3級(jí)届巩,最靠近CPU的緩存稱為L(zhǎng)1,然后依次是L2份乒,L3和主內(nèi)存恕汇;如圖所示:



?
?由于程序指令和程序數(shù)據(jù)的行為和熱點(diǎn)分布差異很大,因此L1 Cache又被劃分成了L1i(i是instruction的首字母)和L1d(d是data的首字母)這兩種有個(gè)字專門用途的緩存或辖,CPU Cache又是由很多個(gè)Cache Line構(gòu)成的瘾英,Cache Line可以認(rèn)為是CPU Cache中的最小緩存單位,目前主流CPU Cache的Cache Line大小都是64字節(jié)颂暇,CPU Cache模型如圖:



?L1缺谴、L2、L3級(jí)Cache出現(xiàn)是為了解決CPU直接訪問(wèn)內(nèi)存效率低下問(wèn)題的蟀架,程序在運(yùn)行的過(guò)程中瓣赂,會(huì)將運(yùn)算所需的數(shù)據(jù)從主存復(fù)制一份到CPU Cache中榆骚,這樣CPU進(jìn)行計(jì)算時(shí)就可以直接對(duì)CPU Cache中的數(shù)據(jù)進(jìn)行讀取和寫入片拍,當(dāng)運(yùn)算結(jié)束后,再將CPU Cache中最新數(shù)據(jù)刷新到主內(nèi)存中妓肢,CPU通過(guò)直接訪問(wèn)Cache的方式替代直接訪問(wèn)主存的方式極大地提高CPU的吞吐能力捌省。

3.2 CPU 緩存一致性問(wèn)題

?雖然緩存的出現(xiàn)極大提高了CPU的吞吐能力,但同時(shí)也引入了緩存不一致的問(wèn)題碉钠,比如i++這個(gè)操作纲缓,在程序運(yùn)行過(guò)程中卷拘,首先需要將主內(nèi)存中的數(shù)據(jù)復(fù)制一份存放到CPU Cache中,那么CPU 寄存器在進(jìn)行數(shù)值計(jì)算的時(shí)候就直接到Cache中讀取和寫入祝高,當(dāng)整個(gè)過(guò)程運(yùn)算結(jié)束之后再將Cache中的數(shù)據(jù)刷新到主存當(dāng)中栗弟,具體過(guò)程如下。

  1. 讀取主內(nèi)存的i到CPU Cache中工闺。
  2. 對(duì)i進(jìn)行加1操作乍赫。
  3. 將結(jié)果協(xié)會(huì)到CPU Cache中。
  4. 將數(shù)據(jù)刷新到主內(nèi)存中陆蟆。
    ?i++在單線程的情況下不會(huì)出現(xiàn)任何問(wèn)題雷厂,但是在多線程情況下就會(huì)有問(wèn)題,每個(gè)線程都有自己的工作內(nèi)存(本地內(nèi)存叠殷,對(duì)應(yīng)CPU中的Cache)改鲫,變量i會(huì)在多個(gè)線程的本地內(nèi)存中都存在一個(gè)副本。如果同時(shí)有兩個(gè)線程執(zhí)行i++操作林束,假設(shè)i的初始值為0像棘,每一個(gè)線程都從主內(nèi)存中獲取i的值存入CPU Cache中,然后經(jīng)過(guò)計(jì)算再寫入主內(nèi)存中诊县,很有可能i在經(jīng)過(guò)兩次自增之后結(jié)果還是1讲弄,這就是緩存不一問(wèn)致性問(wèn)題。
    ?為了解決緩存不一致性題依痊,通常主流的解決方法有如下兩種:
  • 通過(guò)總線加鎖的方式避除。
  • 通過(guò)緩存一致性協(xié)議。
    ?第一種方式常見(jiàn)于早起的CPU當(dāng)中胸嘁,而且是一種悲觀的實(shí)現(xiàn)方式瓶摆,CPU和其他組件的通信都是通過(guò)總線(數(shù)據(jù)總線,控制總線性宏,地址總線)來(lái)進(jìn)行的群井,如果采用總線加鎖的方式,則會(huì)阻塞其他CPU對(duì)其他組件的訪問(wèn)毫胜,從而使得只有一個(gè)CPU(搶到總線鎖)能夠訪問(wèn)這個(gè)變量的內(nèi)存书斜。這種方式效率低下,所以就有了第二種通過(guò)緩存一致性協(xié)議的方式來(lái)解決不一致的問(wèn)題酵使。
    ?分析緩存一致性協(xié)議之前荐吉,我們來(lái)理解下緩存行,之前也簡(jiǎn)單提到了緩存行的概念:
  • 緩存是分段(line)的口渔,一個(gè)段對(duì)應(yīng)一塊存儲(chǔ)空間样屠,我們稱之為緩存行,它是CPU緩存中可分配的最小存儲(chǔ)單元,大小32字節(jié)痪欲、64字節(jié)悦穿、128字節(jié)不等,這與CPU架構(gòu)有關(guān)业踢,通常來(lái)說(shuō)是64字節(jié)栗柒。當(dāng)CPU看到一條讀取內(nèi)存指令時(shí),它會(huì)把內(nèi)存地址傳遞給一級(jí)數(shù)據(jù)緩存知举,一級(jí)數(shù)據(jù)緩存檢查它是否有這個(gè)內(nèi)存地址對(duì)應(yīng)的緩存段傍衡,如果沒(méi)有就把整個(gè)緩存段從內(nèi)存(或更高一級(jí)的緩存)中加載進(jìn)來(lái)。注意负蠕,這里說(shuō)的是一次加載整個(gè)緩存段蛙埂,這個(gè)也是局部性原理。
    ?緩存一致性協(xié)議有多種遮糖,但是日常處理的大多數(shù)計(jì)算機(jī)設(shè)備都屬于“嗅探(snooping)”協(xié)議绣的,它的基本思想是:
所有的內(nèi)存的傳輸都發(fā)生在一條共享的總線上,而所有的處理器都能看到這條總線:緩存本身是獨(dú)立的欲账,但是內(nèi)存是共享資源屡江,所有的內(nèi)存訪問(wèn)都要經(jīng)過(guò)仲裁(同一個(gè)指令周期中,只有一個(gè)CPU緩存可以讀寫內(nèi)存)赛不。 
CPU緩存不僅僅在做內(nèi)存?zhèn)鬏數(shù)臅r(shí)候才與總線打交道惩嘉,而是不停在嗅探總線上發(fā)生的數(shù)據(jù)交換,跟蹤其他緩存在做什么踢故。所以當(dāng)一個(gè)緩存代表他所屬的處理器去讀寫內(nèi)存時(shí)文黎,其他處理器都會(huì)得到通知,它們以此來(lái)使自己的緩存保持同步殿较。只要某個(gè)處理器一寫內(nèi)存耸峭,其他處理器馬上知道這塊內(nèi)存在它們的緩存段中已失效。

?在緩存一致性協(xié)議中最為出名的是Intel的MESI協(xié)議淋纲,MESI協(xié)議保證了每一個(gè)緩存中使用的共享變量副本都是一致的劳闹,它的大致意思是,當(dāng)CPU再操作Cache中的數(shù)據(jù)時(shí)洽瞬,如果發(fā)現(xiàn)該變量是一個(gè)共享變量本涕,也就是說(shuō)在其他的CPU Cache中也存在一個(gè)副本,那么進(jìn)行如下操作:

  1. 讀取操作伙窃,不做任何處理菩颖,只是將Cache中的數(shù)據(jù)讀取到寄存器。
  2. 寫入操作对供,發(fā)出信號(hào)通知其他CPU將該變量的Cache line置為無(wú)效狀態(tài)位他,其他CPU在進(jìn)行該變量讀取的時(shí)候不得不到主內(nèi)存中再次獲取。

?在MESI協(xié)議中产场,每個(gè)緩存行有4個(gè)狀態(tài)鹅髓,可用2個(gè)bit表示,它們分別是:

狀態(tài) 描述 監(jiān)聽(tīng)任務(wù)
M(Modified) 該Cache Line有效京景,數(shù)據(jù)被修改了窿冯,和內(nèi)存中的數(shù)據(jù)不一致,數(shù)據(jù)只存在于本Cache中 緩存行必須時(shí)刻監(jiān)聽(tīng)所有試圖讀該緩存行相對(duì)就主存的操作确徙,這種操作必須在緩存將該緩存行寫回主存并將狀態(tài)變成S(共享)狀態(tài)之前被延遲執(zhí)行醒串。
E(Exclusive) 該Cache line有效,數(shù)據(jù)和內(nèi)存中的數(shù)據(jù)一致鄙皇,數(shù)據(jù)只存在于本Cache中芜赌。 緩存行也必須監(jiān)聽(tīng)其它緩存讀主存中該緩存行的操作,一旦有這種操作伴逸,該緩存行需要變成S(共享)狀態(tài)缠沈。
S(Shared) 該Cache line有效,數(shù)據(jù)和內(nèi)存中的數(shù)據(jù)一致错蝴,數(shù)據(jù)存在于很多Cache中洲愤。 緩存行也必須監(jiān)聽(tīng)其它緩存使該緩存行無(wú)效或者獨(dú)享該緩存行的請(qǐng)求,并將該緩存行變成無(wú)效(Invalid)顷锰。
I(Invalid) 該Cache line無(wú)效柬赐。 無(wú)

?這里的I、S和M狀態(tài)已經(jīng)有了對(duì)應(yīng)的概念:失效/未載入官紫、干凈以及臟的緩存段肛宋。所以這里新的知識(shí)點(diǎn)只有E狀態(tài),代表獨(dú)占式訪問(wèn)束世,這個(gè)狀態(tài)解決了"在我們開(kāi)始修改某塊內(nèi)存之前悼吱,我們需要告訴其它處理器"這一問(wèn)題:只有當(dāng)緩存行處于E或者M(jìn)狀態(tài)時(shí),處理器才能去寫它良狈,也就是說(shuō)只有在這兩種狀態(tài)下后添,處理器是獨(dú)占這個(gè)緩存行的。當(dāng)處理器想寫某個(gè)緩存行時(shí)薪丁,如果它沒(méi)有獨(dú)占權(quán)遇西,它必須先發(fā)送一條"我要獨(dú)占權(quán)"的請(qǐng)求給總線,這會(huì)通知其它處理器把它們擁有的同一緩存段的拷貝失效(如果有)严嗜。只有在獲得獨(dú)占權(quán)后粱檀,處理器才能開(kāi)始修改數(shù)據(jù)----并且此時(shí)這個(gè)處理器知道,這個(gè)緩存行只有一份拷貝漫玄,在我自己的緩存里茄蚯,所以不會(huì)有任何沖突压彭。

?反之,如果有其它處理器想讀取這個(gè)緩存行(馬上能知道渗常,因?yàn)橐恢痹谛崽娇偩€)壮不,獨(dú)占或已修改的緩存行必須先回到"共享"狀態(tài)。如果是已修改的緩存行皱碘,那么還要先把內(nèi)容回寫到內(nèi)存中询一。

四、volatile關(guān)鍵字深入解析

4.1 volatile關(guān)鍵字的語(yǔ)義

?volatile修飾的實(shí)例變量或者類變量具備如下兩層語(yǔ)義:

  • 保證了不同線程之間對(duì)共享變量操作時(shí)的可見(jiàn)性癌椿,也就是說(shuō)當(dāng)一個(gè)線程修改volatile修飾的變量健蕊,另外一個(gè)線程會(huì)理解看到最新的值。
  • 禁止對(duì)指令進(jìn)行重排序
4.1.1理解volatile保證可見(jiàn)性

?關(guān)于共享變量在多線程間的可見(jiàn)性踢俄,在VolatileFoo例子中已經(jīng)體現(xiàn)的非常透徹了缩功,Updater線程對(duì)init_value變量的每一次更改都會(huì)使得Reader線程能夠看到(在JMM的happens-before的關(guān)于volatile規(guī)則定義),其步驟具體如下:

  1. Reader線程從主內(nèi)存中獲取init_value的值為0都办,并且將其緩存到本地工作內(nèi)存中掂之。
  2. Updater線程將init_value的值在本地工作內(nèi)存中修飾為1,然后立即刷新至主內(nèi)存中脆丁。
  3. Reader線程在本地工作內(nèi)存中的init_value失效(反映到硬件上就是CPU的L1或者L2的Cache Line失效)世舰。
  4. 由于Reader線程工作內(nèi)存的init_value失效,因此需要到主內(nèi)存中重新讀取init_value的值槽卫。
4.1.2理解volatile保證順序性

?volatile關(guān)鍵字對(duì)順序性的保證就比較霸道一點(diǎn)跟压,直接禁止JVM和處理器對(duì)volatile關(guān)鍵字修飾的指令進(jìn)行重排序,但是對(duì)于volatile前后無(wú)依賴關(guān)系的指令則可以隨便怎么排序歼培,比如:

int x = 0;
int y = 1;
volatile int z = 20;
x++;
y--;

?在語(yǔ)句volatile int z= 20之前震蒋,先執(zhí)行x的定義還是先執(zhí)行y的定義,我們并不關(guān)心躲庄,只要能夠百分之百地保證在執(zhí)行到z=20的時(shí)候x=0, y=1查剖,同理,關(guān)于x的自增以及y的自減操作都必須在z=20之后才能發(fā)生噪窘。
?再看另外一個(gè)例子:

private volatile boolean initialized = false;
private Context context;
public Context load() {
  if (!initialized) {
    context = loadContext();
    initialized = true; // 阻止重排序
  }
  return context;
}

?因?yàn)閕nitialized 布爾變量增加了volatile的修飾笋庄,那就意味著initialized = true;的時(shí)候一定是執(zhí)行且完成了對(duì)loadContext()的方法調(diào)用。

4.1.3理解volatile保不保證原子性

?我們也先來(lái)看一個(gè)例子:

/**
 * <Description> <br>
 *
 * @author Sunny<br>
 * @version 1.0<br>
 * @taskId: <br>
 * @createDate 2019/02/24 11:08 <br>
 * @see com.sunny.concurrent.volatilekey <br>
 */
public class VolatileNonAtomic {
    /**
     * 使用volatile修飾共享資源i
     */
    private static volatile int i = 0;
    private static final CountDownLatch latch = new CountDownLatch(10);

    private static void inc() {
        i++;
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int x = 0; x < 1000; x++) {
                    inc();
                }
                /**
                 * 使計(jì)數(shù)器減1
                 */
                latch.countDown();
            }).start();
        }
        // 等待所有的線程完成工作
        latch.await();
        System.out.println(i);
    }
}

?上面的這段代碼創(chuàng)建了10個(gè)線程倔监,每個(gè)線程執(zhí)行1000次對(duì)共享變量i的自增操作直砂,但是最終結(jié)果肯定不一定是10000,而且每次運(yùn)行的結(jié)果也是各不相同浩习,下面來(lái)分析一下其中的原因静暂。
?i++的操作其實(shí)也是由三步組成的,具體如下:

  1. 從主內(nèi)存中獲取i的值谱秽,然后緩存至線程工作內(nèi)存中洽蛀。
  2. 在線程工作內(nèi)存中為i進(jìn)行加1的操作摹迷。
  3. 將i的最新值寫入主內(nèi)存中。

?上面的操作單獨(dú)的每一個(gè)操作都是原子性操作郊供,但是合起來(lái)就不是峡碉,因?yàn)樵趫?zhí)行中途很有可能會(huì)被其他線程打斷,例如如下操作情況颂碘。

  1. 假設(shè)此時(shí)i的值為100,線程A要對(duì)變量i執(zhí)行自增操作椅挣,首先它需要到主內(nèi)存中讀取i的值头岔,可是此時(shí)由于CPU時(shí)間片調(diào)度的關(guān)系,執(zhí)行權(quán)切換到了線程B鼠证,A線程進(jìn)入了RUNNABLE狀態(tài)而不是RUNNING狀態(tài)峡竣。
  2. 線程B同樣需要從主內(nèi)存中讀取i的值,由于線程A沒(méi)有對(duì)i做過(guò)任何修改操作量九,因此此時(shí)B獲取到的i仍然是100.
  3. 線程B工作內(nèi)存中為i執(zhí)行了加1操作适掰,但是未刷新至主內(nèi)存中。
  4. CPU時(shí)間片的調(diào)度又將執(zhí)行權(quán)給了線程A荠列,A線程直接對(duì)工作線程中的100進(jìn)行加1運(yùn)行(因?yàn)锳線程已經(jīng)從主內(nèi)存中讀取了i的值)类浪,由于B線程并未寫入i的最新值,因此A線程工作空間中的100不會(huì)被失效肌似。
  5. 線程A將i=101寫入主內(nèi)存之中费就。
  6. 線程B將i=101寫入到主內(nèi)存中。
    ?這樣兩次運(yùn)算實(shí)際上只對(duì)i進(jìn)行了一次數(shù)值的修改變化川队。

4.2 volatile的原理和實(shí)現(xiàn)機(jī)制

?通過(guò)下面的例子力细,我們將從Java生成的匯編指令來(lái)解析帶volatile關(guān)鍵字和不帶的差異以及相關(guān)原理,例子如下:

/**
 * <Description> <br>
 *
 * @author Sunny<br>
 * @version 1.0<br>
 * @taskId: <br>
 * @createDate 2019/02/19 14:22 <br>
 * @see com.sunny.concurrent.volatilekey <br>
 */
public class VolatileSingleton {
    public static VolatileSingleton instance;

    public static VolatileSingleton getInstance(){
        if(instance == null){
            synchronized(VolatileSingleton.class){
                if(instance== null){
                    instance = new VolatileSingleton();
                }
            }
        }
        return instance;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        VolatileSingleton.getInstance();
    }

}

?首先instance屬性不帶volatile參數(shù)固额,在執(zhí)行main方法前眠蚂,我們?cè)黾覬VM參數(shù):

-server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=dontinline,*VolatileSingleton.getInstance -XX:CompileCommand=compileonly,*VolatileSingleton.getInstance -XX:+PrintAssembly

?其中,參數(shù) -Xcomp 是讓虛擬機(jī)以編譯模式執(zhí)行代碼斗躏,這樣代碼可以偷懶逝慧,不需要執(zhí)行足夠次數(shù)來(lái)預(yù)熱都能觸發(fā) JIT 編譯。兩個(gè) -XX:CompileCommand 意思是讓編譯器不要內(nèi)聯(lián) getInstance() 并且只編譯 getInstance()啄糙,-XX:+PrintAssembly 就是輸出反匯編內(nèi)容馋艺。如果一切順利的話,控制臺(tái)會(huì)出現(xiàn)如下輸出:

Decoding compiled method 0x0000000002b30c50:
Code:
[Entry Point]
[Verified Entry Point]
[Constants]
  # {method} {0x0000000016f42ab8} 'getInstance' '()Lcom/sunny/concurrent/volatilekey/VolatileSingleton;' in 'com/sunny/concurrent/volatilekey/VolatileSingleton'
  #           [sp+0x50]  (sp of caller)
  0x0000000002b30dc0: mov    %eax,-0x6000(%rsp)
  0x0000000002b30dc7: push   %rbp
  0x0000000002b30dc8: sub    $0x40,%rsp         ;*synchronization entry
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@-1 (line 16)

  0x0000000002b30dcc: movabs $0xd6556b28,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30dd6: mov    0x68(%r10),%r11d   ;*getstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@0 (line 16)

  0x0000000002b30dda: test   %r11d,%r11d
  0x0000000002b30ddd: je     0x0000000002b30dee
  0x0000000002b30ddf: mov    %r11,%rax          ;*getstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@37 (line 23)

  0x0000000002b30de2: add    $0x40,%rsp
  0x0000000002b30de6: pop    %rbp
  0x0000000002b30de7: test   %eax,-0x2940ded(%rip)        # 0x00000000001f0000
                                                ;   {poll_return}
  0x0000000002b30ded: retq   
  0x0000000002b30dee: mov    (%r10),%rax
  0x0000000002b30df1: mov    %rax,%r10
  0x0000000002b30df4: and    $0x7,%r10
  0x0000000002b30df8: cmp    $0x5,%r10
  0x0000000002b30dfc: jne    0x0000000002b30f21
  0x0000000002b30e02: mov    $0x200003df,%r11d  ;   {metadata('java/lang/Class')}
  0x0000000002b30e08: movabs $0x0,%r10
  0x0000000002b30e12: lea    (%r10,%r11,8),%r10
  0x0000000002b30e16: mov    0xa8(%r10),%r10
  0x0000000002b30e1d: mov    %r10,%r11
  0x0000000002b30e20: or     %r15,%r11
  0x0000000002b30e23: mov    %r11,%r8
  0x0000000002b30e26: xor    %rax,%r8
  0x0000000002b30e29: test   $0xffffffffffffff87,%r8
  0x0000000002b30e30: jne    0x0000000002b30f99  ;*monitorenter
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@10 (line 17)

  0x0000000002b30e36: mov    $0x7,%ebp
  0x0000000002b30e3b: movabs $0xd6556b28,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30e45: cmp    0x68(%r10),%r12d
  0x0000000002b30e49: je     0x0000000002b30e75
  0x0000000002b30e4b: movabs $0xd6556b28,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30e55: and    (%r10),%rbp
  0x0000000002b30e58: cmp    $0x5,%rbp
  0x0000000002b30e5c: jne    0x0000000002b30fd2  ;*monitorexit
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@28 (line 21)

  0x0000000002b30e62: movabs $0xd6556b28,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30e6c: mov    0x68(%r10),%r11d   ;*getstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@37 (line 23)

  0x0000000002b30e70: jmpq   0x0000000002b30ddf
  0x0000000002b30e75: mov    0x60(%r15),%rax
  0x0000000002b30e79: mov    %rax,%r10
  0x0000000002b30e7c: add    $0x10,%r10
  0x0000000002b30e80: cmp    0x70(%r15),%r10
  0x0000000002b30e84: jae    0x0000000002b30eff
  0x0000000002b30e86: mov    %r10,0x60(%r15)
  0x0000000002b30e8a: prefetchw 0xc0(%r10)
  0x0000000002b30e92: mov    $0x2000c105,%r11d  ;   {metadata('com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30e98: movabs $0x0,%r10
  0x0000000002b30ea2: lea    (%r10,%r11,8),%r10
  0x0000000002b30ea6: mov    0xa8(%r10),%r10
  0x0000000002b30ead: mov    %r10,(%rax)
  0x0000000002b30eb0: movl   $0x2000c105,0x8(%rax)  ;   {metadata('com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30eb7: mov    %r12d,0xc(%rax)
  0x0000000002b30ebb: mov    %rax,%r10
  0x0000000002b30ebe: mov    %r10,0x20(%rsp)    ;*new  ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@17 (line 19)

  0x0000000002b30ec3: mov    %r10,%rdx
  0x0000000002b30ec6: nop
  0x0000000002b30ec7: callq  0x0000000002a661a0  ; OopMap{[32]=Oop off=268}
                                                ;*invokespecial <init>
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@21 (line 19)
                                                ;   {optimized virtual_call}
  0x0000000002b30ecc: movabs $0xd6556b28,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30ed6: mov    0x20(%rsp),%r11
  0x0000000002b30edb: mov    %r11,%r8
  0x0000000002b30ede: movabs $0xd6556b28,%r11   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30ee8: mov    %r8d,0x68(%r11)
  0x0000000002b30eec: shr    $0x9,%r10
  0x0000000002b30ef0: mov    $0x119ce000,%r11d
  0x0000000002b30ef6: mov    %r12b,(%r11,%r10,1)  ;*putstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@24 (line 19)

  0x0000000002b30efa: jmpq   0x0000000002b30e4b
  0x0000000002b30eff: movabs $0x100060828,%rdx  ;   {metadata('com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30f09: xchg   %ax,%ax
  0x0000000002b30f0b: callq  0x0000000002a8f3e0  ; OopMap{off=336}
                                                ;*new  ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@17 (line 19)
                                                ;   {runtime_call}
  0x0000000002b30f10: jmp    0x0000000002b30ebb
  0x0000000002b30f12: movabs $0xd6556b28,%r11   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30f1c: lock cmpxchg %r10,(%r11)
  0x0000000002b30f21: movabs $0xd6556b28,%r11   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30f2b: lea    0x30(%rsp),%rbx
  0x0000000002b30f30: mov    (%r11),%rax
  0x0000000002b30f33: test   $0x2,%rax
  0x0000000002b30f39: jne    0x0000000002b30f5f
  0x0000000002b30f3b: or     $0x1,%rax
  0x0000000002b30f3f: mov    %rax,(%rbx)
  0x0000000002b30f42: lock cmpxchg %rbx,(%r11)
  0x0000000002b30f47: je     0x0000000002b30f78
  0x0000000002b30f4d: sub    %rsp,%rax
  0x0000000002b30f50: and    $0xfffffffffffff007,%rax
  0x0000000002b30f57: mov    %rax,(%rbx)
  0x0000000002b30f5a: jmpq   0x0000000002b30f78
  0x0000000002b30f5f: movq   $0x3,(%rbx)
  0x0000000002b30f66: mov    %rax,%rbx
  0x0000000002b30f69: mov    0x16(%rbx),%rax
  0x0000000002b30f6d: test   %rax,%rax
  0x0000000002b30f70: jne    0x0000000002b30f78
  0x0000000002b30f72: lock cmpxchg %r15,0x16(%rbx)
  0x0000000002b30f78: je     0x0000000002b30e36
  0x0000000002b30f7e: movabs $0xd6556b28,%rdx   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30f88: lea    0x30(%rsp),%r8
  0x0000000002b30f8d: xchg   %ax,%ax
  0x0000000002b30f8f: callq  0x0000000002a92220  ; OopMap{off=468}
                                                ;*monitorenter
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@10 (line 17)
                                                ;   {runtime_call}
  0x0000000002b30f94: jmpq   0x0000000002b30e36
  0x0000000002b30f99: test   $0x7,%r8
  0x0000000002b30fa0: jne    0x0000000002b30f12
  0x0000000002b30fa6: test   $0x300,%r8
  0x0000000002b30fad: jne    0x0000000002b30fbc
  0x0000000002b30faf: and    $0x37f,%rax
  0x0000000002b30fb6: mov    %rax,%r11
  0x0000000002b30fb9: or     %r15,%r11
  0x0000000002b30fbc: movabs $0xd6556b28,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30fc6: lock cmpxchg %r11,(%r10)
  0x0000000002b30fcb: jne    0x0000000002b30f7e
  0x0000000002b30fcd: jmpq   0x0000000002b30e36
  0x0000000002b30fd2: movabs $0xd6556b28,%r11   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b30fdc: lea    0x30(%rsp),%rax
  0x0000000002b30fe1: cmpq   $0x0,(%rax)
  0x0000000002b30fe8: je     0x0000000002b31062
  0x0000000002b30fee: mov    (%r11),%r10
  0x0000000002b30ff1: test   $0x2,%r10
  0x0000000002b30ff8: je     0x0000000002b3105a
  0x0000000002b30ffa: mov    0x16(%r10),%rax
  0x0000000002b30ffe: xor    %r15,%rax
  0x0000000002b31001: or     0x26(%r10),%rax
  0x0000000002b31005: jne    0x0000000002b31062
  0x0000000002b31007: mov    0x36(%r10),%rax
  0x0000000002b3100b: or     0x3e(%r10),%rax
  0x0000000002b3100f: jne    0x0000000002b3101b
  0x0000000002b31011: movq   $0x0,0x16(%r10)
  0x0000000002b31019: jmp    0x0000000002b31062
  0x0000000002b3101b: cmpq   $0x0,0x46(%r10)
  0x0000000002b31023: je     0x0000000002b3104e
  0x0000000002b31025: movq   $0x0,0x16(%r10)
  0x0000000002b3102d: lock addl $0x0,(%rsp)
  0x0000000002b31032: cmpq   $0x0,0x46(%r10)
  0x0000000002b3103a: jne    0x0000000002b31053
  0x0000000002b3103c: movabs $0x0,%rax
  0x0000000002b31046: lock cmpxchg %r15,0x16(%r10)
  0x0000000002b3104c: jne    0x0000000002b31053
  0x0000000002b3104e: or     $0x1,%eax
  0x0000000002b31051: jmp    0x0000000002b31062
  0x0000000002b31053: test   $0x0,%eax
  0x0000000002b31058: jmp    0x0000000002b31062
  0x0000000002b3105a: mov    (%rax),%r10
  0x0000000002b3105d: lock cmpxchg %r10,(%r11)
  0x0000000002b31062: je     0x0000000002b30e62
  0x0000000002b31068: movabs $0xd6556b28,%rcx   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b31072: lea    0x30(%rsp),%rdx    ;*monitorenter
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@10 (line 17)

  0x0000000002b31077: movabs $0x650fcce0,%r10
  0x0000000002b31081: callq  *%r10              ;*monitorexit
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@28 (line 21)

  0x0000000002b31084: jmpq   0x0000000002b30e62  ;*new
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@17 (line 19)

  0x0000000002b31089: mov    %rax,%rbx
  0x0000000002b3108c: jmp    0x0000000002b31091  ;*invokespecial <init>
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@21 (line 19)

  0x0000000002b3108e: mov    %rax,%rbx
  0x0000000002b31091: movabs $0xd6556b28,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b3109b: and    (%r10),%rbp
  0x0000000002b3109e: cmp    $0x5,%rbp
  0x0000000002b310a2: jne    0x0000000002b310b1  ;*monitorexit
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@34 (line 21)

  0x0000000002b310a4: mov    %rbx,%rdx
  0x0000000002b310a7: add    $0x40,%rsp
  0x0000000002b310ab: pop    %rbp
  0x0000000002b310ac: jmpq   0x0000000002a92320  ;   {runtime_call}
  0x0000000002b310b1: movabs $0xd6556b28,%r11   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b310bb: lea    0x30(%rsp),%rax
  0x0000000002b310c0: cmpq   $0x0,(%rax)
  0x0000000002b310c7: je     0x0000000002b31141
  0x0000000002b310cd: mov    (%r11),%r10
  0x0000000002b310d0: test   $0x2,%r10
  0x0000000002b310d7: je     0x0000000002b31139
  0x0000000002b310d9: mov    0x16(%r10),%rax
  0x0000000002b310dd: xor    %r15,%rax
  0x0000000002b310e0: or     0x26(%r10),%rax
  0x0000000002b310e4: jne    0x0000000002b31141
  0x0000000002b310e6: mov    0x36(%r10),%rax
  0x0000000002b310ea: or     0x3e(%r10),%rax
  0x0000000002b310ee: jne    0x0000000002b310fa
  0x0000000002b310f0: movq   $0x0,0x16(%r10)
  0x0000000002b310f8: jmp    0x0000000002b31141
  0x0000000002b310fa: cmpq   $0x0,0x46(%r10)
  0x0000000002b31102: je     0x0000000002b3112d
  0x0000000002b31104: movq   $0x0,0x16(%r10)
  0x0000000002b3110c: lock addl $0x0,(%rsp)
  0x0000000002b31111: cmpq   $0x0,0x46(%r10)
  0x0000000002b31119: jne    0x0000000002b31132
  0x0000000002b3111b: movabs $0x0,%rax
  0x0000000002b31125: lock cmpxchg %r15,0x16(%r10)
  0x0000000002b3112b: jne    0x0000000002b31132
  0x0000000002b3112d: or     $0x1,%eax
  0x0000000002b31130: jmp    0x0000000002b31141
  0x0000000002b31132: test   $0x0,%eax
  0x0000000002b31137: jmp    0x0000000002b31141
  0x0000000002b31139: mov    (%rax),%r10
  0x0000000002b3113c: lock cmpxchg %r10,(%r11)
  0x0000000002b31141: je     0x0000000002b310a4
  0x0000000002b31147: movabs $0xd6556b28,%rcx   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002b31151: lea    0x30(%rsp),%rdx    ;*monitorenter
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@10 (line 17)

  0x0000000002b31156: movabs $0x650fcce0,%r10
  0x0000000002b31160: callq  *%r10              ;*monitorexit
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@34 (line 21)

  0x0000000002b31163: jmpq   0x0000000002b310a4
[Stub Code]
  0x0000000002b31180: movabs $0x0,%rbx          ;   {no_reloc}
  0x0000000002b3118a: jmpq   0x0000000002b3118a  ;   {runtime_call}
[Exception Handler]
  0x0000000002b3118f: jmpq   0x0000000002a8f4a0  ;   {runtime_call}
[Deopt Handler Code]
  0x0000000002b31194: callq  0x0000000002b31199
  0x0000000002b31199: subq   $0x5,(%rsp)
  0x0000000002b3119e: jmpq   0x0000000002a67600  ;   {runtime_call}
  0x0000000002b311a3: hlt    
  0x0000000002b311a4: hlt    
  0x0000000002b311a5: hlt    
  0x0000000002b311a6: hlt    
  0x0000000002b311a7: hlt    
Java HotSpot(TM) 64-Bit Server VM warning: PrintAssembly is enabled; turning on DebugNonSafepoints to gain additional output

Process finished with exit code 0

?把instance屬性增加volatile關(guān)鍵字:

public volatile static VolatileSingleton instance;

?重新執(zhí)行main方法迈套,控制臺(tái)打印如下信息:

CompilerOracle: dontinline *VolatileSingleton.getInstance
CompilerOracle: compileonly *VolatileSingleton.getInstance
Loaded disassembler from C:\ProgramFiles\Java\jdk1.8.0_144\jre\bin\server\hsdis-amd64.dll
Decoding compiled method 0x0000000002f3d490:
Code:
[Disassembling for mach='i386:x86-64']
[Entry Point]
[Verified Entry Point]
[Constants]
  # {method} {0x0000000017352ab8} 'getInstance' '()Lcom/sunny/concurrent/volatilekey/VolatileSingleton;' in 'com/sunny/concurrent/volatilekey/VolatileSingleton'
  #           [sp+0x50]  (sp of caller)
  0x0000000002f3d620: mov    %eax,-0x6000(%rsp)
  0x0000000002f3d627: push   %rbp
  0x0000000002f3d628: sub    $0x40,%rsp
  0x0000000002f3d62c: movabs $0x17352c90,%rax   ;   {metadata(method data for {method} {0x0000000017352ab8} 'getInstance' '()Lcom/sunny/concurrent/volatilekey/VolatileSingleton;' in 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d636: mov    0xdc(%rax),%edx
  0x0000000002f3d63c: add    $0x8,%edx
  0x0000000002f3d63f: mov    %edx,0xdc(%rax)
  0x0000000002f3d645: movabs $0x17352ab0,%rax   ;   {metadata({method} {0x0000000017352ab8} 'getInstance' '()Lcom/sunny/concurrent/volatilekey/VolatileSingleton;' in 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d64f: and    $0x0,%edx
  0x0000000002f3d652: cmp    $0x0,%edx
  0x0000000002f3d655: je     0x0000000002f3d90e
  0x0000000002f3d65b: movabs $0xd6556ab8,%rax   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d665: mov    0x68(%rax),%eax    ;*getstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@0 (line 16)

  0x0000000002f3d668: cmp    $0x0,%rax
  0x0000000002f3d66c: movabs $0x17352c90,%rax   ;   {metadata(method data for {method} {0x0000000017352ab8} 'getInstance' '()Lcom/sunny/concurrent/volatilekey/VolatileSingleton;' in 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d676: movabs $0x108,%rdx
  0x0000000002f3d680: jne    0x0000000002f3d690
  0x0000000002f3d686: movabs $0x118,%rdx
  0x0000000002f3d690: mov    (%rax,%rdx,1),%rsi
  0x0000000002f3d694: lea    0x1(%rsi),%rsi
  0x0000000002f3d698: mov    %rsi,(%rax,%rdx,1)
  0x0000000002f3d69c: jne    0x0000000002f3d894  ;*ifnonnull
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@3 (line 16)

  0x0000000002f3d6a2: movabs $0xd6556ab8,%rdx   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d6ac: lea    0x28(%rsp),%rsi
  0x0000000002f3d6b1: mov    %rdx,0x8(%rsi)
  0x0000000002f3d6b5: mov    (%rdx),%rax        ; implicit exception: dispatches to 0x0000000002f3d925
  0x0000000002f3d6b8: mov    %rax,%rdi
  0x0000000002f3d6bb: and    $0x7,%rdi
  0x0000000002f3d6bf: cmp    $0x5,%rdi
  0x0000000002f3d6c3: jne    0x0000000002f3d74a
  0x0000000002f3d6c9: mov    0x8(%rdx),%edi
  0x0000000002f3d6cc: shl    $0x3,%rdi
  0x0000000002f3d6d0: mov    0xa8(%rdi),%rdi
  0x0000000002f3d6d7: or     %r15,%rdi
  0x0000000002f3d6da: xor    %rax,%rdi
  0x0000000002f3d6dd: and    $0xffffffffffffff87,%rdi
  0x0000000002f3d6e1: je     0x0000000002f3d772
  0x0000000002f3d6e7: test   $0x7,%rdi
  0x0000000002f3d6ee: jne    0x0000000002f3d737
  0x0000000002f3d6f0: test   $0x300,%rdi
  0x0000000002f3d6f7: jne    0x0000000002f3d716
  0x0000000002f3d6f9: and    $0x37f,%rax
  0x0000000002f3d700: mov    %rax,%rdi
  0x0000000002f3d703: or     %r15,%rdi
  0x0000000002f3d706: lock cmpxchg %rdi,(%rdx)
  0x0000000002f3d70b: jne    0x0000000002f3d92a
  0x0000000002f3d711: jmpq   0x0000000002f3d772
  0x0000000002f3d716: mov    0x8(%rdx),%edi
  0x0000000002f3d719: shl    $0x3,%rdi
  0x0000000002f3d71d: mov    0xa8(%rdi),%rdi
  0x0000000002f3d724: or     %r15,%rdi
  0x0000000002f3d727: lock cmpxchg %rdi,(%rdx)
  0x0000000002f3d72c: jne    0x0000000002f3d92a
  0x0000000002f3d732: jmpq   0x0000000002f3d772
  0x0000000002f3d737: mov    0x8(%rdx),%edi
  0x0000000002f3d73a: shl    $0x3,%rdi
  0x0000000002f3d73e: mov    0xa8(%rdi),%rdi
  0x0000000002f3d745: lock cmpxchg %rdi,(%rdx)
  0x0000000002f3d74a: mov    (%rdx),%rax
  0x0000000002f3d74d: or     $0x1,%rax
  0x0000000002f3d751: mov    %rax,(%rsi)
  0x0000000002f3d754: lock cmpxchg %rsi,(%rdx)
  0x0000000002f3d759: je     0x0000000002f3d772
  0x0000000002f3d75f: sub    %rsp,%rax
  0x0000000002f3d762: and    $0xfffffffffffff007,%rax
  0x0000000002f3d769: mov    %rax,(%rsi)
  0x0000000002f3d76c: jne    0x0000000002f3d92a  ;*monitorenter
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@10 (line 17)

  0x0000000002f3d772: movabs $0xd6556ab8,%rdx   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d77c: mov    0x68(%rdx),%edx    ;*getstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@11 (line 18)

  0x0000000002f3d77f: cmp    $0x0,%rdx
  0x0000000002f3d783: movabs $0x17352c90,%rdx   ;   {metadata(method data for {method} {0x0000000017352ab8} 'getInstance' '()Lcom/sunny/concurrent/volatilekey/VolatileSingleton;' in 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d78d: movabs $0x128,%rsi
  0x0000000002f3d797: jne    0x0000000002f3d7a7
  0x0000000002f3d79d: movabs $0x138,%rsi
  0x0000000002f3d7a7: mov    (%rdx,%rsi,1),%rdi
  0x0000000002f3d7ab: lea    0x1(%rdi),%rdi
  0x0000000002f3d7af: mov    %rdi,(%rdx,%rsi,1)
  0x0000000002f3d7b3: jne    0x0000000002f3d849  ;*ifnonnull
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@14 (line 18)

  0x0000000002f3d7b9: movabs $0x100060828,%rdx  ;   {metadata('com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d7c3: mov    0x60(%r15),%rax
  0x0000000002f3d7c7: lea    0x10(%rax),%rdi
  0x0000000002f3d7cb: cmp    0x70(%r15),%rdi
  0x0000000002f3d7cf: ja     0x0000000002f3d93d
  0x0000000002f3d7d5: mov    %rdi,0x60(%r15)
  0x0000000002f3d7d9: mov    0xa8(%rdx),%rcx
  0x0000000002f3d7e0: mov    %rcx,(%rax)
  0x0000000002f3d7e3: mov    %rdx,%rcx
  0x0000000002f3d7e6: shr    $0x3,%rcx
  0x0000000002f3d7ea: mov    %ecx,0x8(%rax)
  0x0000000002f3d7ed: xor    %rcx,%rcx
  0x0000000002f3d7f0: mov    %ecx,0xc(%rax)
  0x0000000002f3d7f3: xor    %rcx,%rcx          ;*new  ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@17 (line 19)

  0x0000000002f3d7f6: mov    %rax,%rdx
  0x0000000002f3d7f9: movabs $0x17352c90,%rsi   ;   {metadata(method data for {method} {0x0000000017352ab8} 'getInstance' '()Lcom/sunny/concurrent/volatilekey/VolatileSingleton;' in 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d803: addq   $0x1,0x148(%rsi)
  0x0000000002f3d80b: mov    %rax,%rdx          ;*invokespecial <init>
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@21 (line 19)

  0x0000000002f3d80e: mov    %rax,0x20(%rsp)
  0x0000000002f3d817: callq  0x0000000002e761a0  ; OopMap{[32]=Oop [48]=Oop off=508}
                                                ;*invokespecial <init>
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@21 (line 19)
                                                ;   {optimized virtual_call}
  0x0000000002f3d81c: movabs $0xd6556ab8,%rax   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d826: mov    0x20(%rsp),%rsi
  0x0000000002f3d82b: mov    %rsi,%r10
  0x0000000002f3d82e: mov    %r10d,0x68(%rax)
  0x0000000002f3d832: shr    $0x9,%rax
  0x0000000002f3d836: movabs $0x11dde000,%rsi
  0x0000000002f3d840: movb   $0x0,(%rax,%rsi,1)
  0x0000000002f3d844: lock addl $0x0,(%rsp)     ;*putstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@24 (line 19)

  0x0000000002f3d849: movabs $0xd6556ab8,%rax   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d853: lea    0x28(%rsp),%rax
  0x0000000002f3d858: mov    0x8(%rax),%rdi
  0x0000000002f3d85c: mov    (%rdi),%rsi
  0x0000000002f3d85f: and    $0x7,%rsi
  0x0000000002f3d863: cmp    $0x5,%rsi
  0x0000000002f3d867: je     0x0000000002f3d884
  0x0000000002f3d86d: mov    (%rax),%rsi
  0x0000000002f3d870: test   %rsi,%rsi
  0x0000000002f3d873: je     0x0000000002f3d884
  0x0000000002f3d879: lock cmpxchg %rsi,(%rdi)
  0x0000000002f3d87e: jne    0x0000000002f3d94a  ;*monitorexit
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@28 (line 21)

  0x0000000002f3d884: movabs $0x17352c90,%rax   ;   {metadata(method data for {method} {0x0000000017352ab8} 'getInstance' '()Lcom/sunny/concurrent/volatilekey/VolatileSingleton;' in 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d88e: incl   0x158(%rax)        ;*goto
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@29 (line 21)

  0x0000000002f3d894: movabs $0xd6556ab8,%rax   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d89e: mov    0x68(%rax),%eax    ;*getstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@37 (line 23)

  0x0000000002f3d8a1: add    $0x40,%rsp
  0x0000000002f3d8a5: pop    %rbp
  0x0000000002f3d8a6: test   %eax,-0x24dd7ac(%rip)        # 0x0000000000a60100
                                                ;   {poll_return}
  0x0000000002f3d8ac: retq                      ;*areturn
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@40 (line 23)

  0x0000000002f3d8ad: mov    0x2a8(%r15),%rax
  0x0000000002f3d8b4: xor    %r10,%r10
  0x0000000002f3d8b7: mov    %r10,0x2a8(%r15)
  0x0000000002f3d8be: xor    %r10,%r10
  0x0000000002f3d8c1: mov    %r10,0x2b0(%r15)
  0x0000000002f3d8c8: mov    %rax,%rsi
  0x0000000002f3d8cb: movabs $0xd6556ab8,%rax   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f3d8d5: lea    0x28(%rsp),%rax
  0x0000000002f3d8da: mov    0x8(%rax),%rbx
  0x0000000002f3d8de: mov    (%rbx),%rdi
  0x0000000002f3d8e1: and    $0x7,%rdi
  0x0000000002f3d8e5: cmp    $0x5,%rdi
  0x0000000002f3d8e9: je     0x0000000002f3d906
  0x0000000002f3d8ef: mov    (%rax),%rdi
  0x0000000002f3d8f2: test   %rdi,%rdi
  0x0000000002f3d8f5: je     0x0000000002f3d906
  0x0000000002f3d8fb: lock cmpxchg %rdi,(%rbx)
  0x0000000002f3d900: jne    0x0000000002f3d95d  ;*monitorexit
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@34 (line 21)

  0x0000000002f3d906: mov    %rsi,%rax
  0x0000000002f3d909: jmpq   0x0000000002f3d998
  0x0000000002f3d90e: mov    %rax,0x8(%rsp)
  0x0000000002f3d913: movq   $0xffffffffffffffff,(%rsp)
  0x0000000002f3d91b: callq  0x0000000002f32760  ; OopMap{off=768}
                                                ;*synchronization entry
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@-1 (line 16)
                                                ;   {runtime_call}
  0x0000000002f3d920: jmpq   0x0000000002f3d65b
  0x0000000002f3d925: callq  0x0000000002ea1200  ; OopMap{rdx=Oop off=778}
                                                ;*monitorenter
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@10 (line 17)
                                                ;   {runtime_call}
  0x0000000002f3d92a: mov    %rdx,0x8(%rsp)
  0x0000000002f3d92f: mov    %rsi,(%rsp)
  0x0000000002f3d933: callq  0x0000000002f30a60  ; OopMap{rdx=Oop [48]=Oop off=792}
                                                ;*monitorenter
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@10 (line 17)
                                                ;   {runtime_call}
  0x0000000002f3d938: jmpq   0x0000000002f3d772
  0x0000000002f3d93d: mov    %rdx,%rdx
  0x0000000002f3d940: callq  0x0000000002ea08c0  ; OopMap{[48]=Oop off=805}
                                                ;*new  ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@17 (line 19)
                                                ;   {runtime_call}
  0x0000000002f3d945: jmpq   0x0000000002f3d7f6
  0x0000000002f3d94a: lea    0x28(%rsp),%rax
  0x0000000002f3d94f: mov    %rax,(%rsp)
  0x0000000002f3d953: callq  0x0000000002f30e60  ;   {runtime_call}
  0x0000000002f3d958: jmpq   0x0000000002f3d884
  0x0000000002f3d95d: lea    0x28(%rsp),%rax
  0x0000000002f3d962: mov    %rax,(%rsp)
  0x0000000002f3d966: callq  0x0000000002f30e60  ;   {runtime_call}
  0x0000000002f3d96b: jmp    0x0000000002f3d906
  0x0000000002f3d96d: nop
  0x0000000002f3d96e: nop
  0x0000000002f3d96f: mov    0x2a8(%r15),%rax
  0x0000000002f3d976: movabs $0x0,%r10
  0x0000000002f3d980: mov    %r10,0x2a8(%r15)
  0x0000000002f3d987: movabs $0x0,%r10
  0x0000000002f3d991: mov    %r10,0x2b0(%r15)
  0x0000000002f3d998: add    $0x40,%rsp
  0x0000000002f3d99c: pop    %rbp
  0x0000000002f3d99d: jmpq   0x0000000002e9fbe0  ;   {runtime_call}
[Stub Code]
  0x0000000002f3d9c0: nop                       ;   {no_reloc}
  0x0000000002f3d9c5: movabs $0x0,%rbx          ;   {static_stub}
  0x0000000002f3d9cf: jmpq   0x0000000002f3d9cf  ;   {runtime_call}
[Exception Handler]
  0x0000000002f3d9d4: callq  0x0000000002ea2b20  ;   {runtime_call}
  0x0000000002f3d9d9: mov    %rsp,-0x28(%rsp)
  0x0000000002f3d9de: sub    $0x80,%rsp
  0x0000000002f3d9e5: mov    %rax,0x78(%rsp)
  0x0000000002f3d9ea: mov    %rcx,0x70(%rsp)
  0x0000000002f3d9ef: mov    %rdx,0x68(%rsp)
  0x0000000002f3d9f4: mov    %rbx,0x60(%rsp)
  0x0000000002f3d9f9: mov    %rbp,0x50(%rsp)
  0x0000000002f3d9fe: mov    %rsi,0x48(%rsp)
  0x0000000002f3da03: mov    %rdi,0x40(%rsp)
  0x0000000002f3da08: mov    %r8,0x38(%rsp)
  0x0000000002f3da0d: mov    %r9,0x30(%rsp)
  0x0000000002f3da12: mov    %r10,0x28(%rsp)
  0x0000000002f3da17: mov    %r11,0x20(%rsp)
  0x0000000002f3da1c: mov    %r12,0x18(%rsp)
  0x0000000002f3da21: mov    %r13,0x10(%rsp)
  0x0000000002f3da26: mov    %r14,0x8(%rsp)
  0x0000000002f3da2b: mov    %r15,(%rsp)
  0x0000000002f3da2f: movabs $0x65509e40,%rcx   ;   {external_word}
  0x0000000002f3da39: movabs $0x2f3d9d9,%rdx    ;   {internal_word}
  0x0000000002f3da43: mov    %rsp,%r8
  0x0000000002f3da46: and    $0xfffffffffffffff0,%rsp
  0x0000000002f3da4a: callq  0x00000000651c3cf0  ;   {runtime_call}
  0x0000000002f3da4f: hlt    
[Deopt Handler Code]
  0x0000000002f3da50: movabs $0x2f3da50,%r10    ;   {section_word}
  0x0000000002f3da5a: push   %r10
  0x0000000002f3da5c: jmpq   0x0000000002e77600  ;   {runtime_call}
Decoding compiled method 0x0000000002f40c90:
Code:
[Entry Point]
[Verified Entry Point]
[Constants]
  # {method} {0x0000000017352ab8} 'getInstance' '()Lcom/sunny/concurrent/volatilekey/VolatileSingleton;' in 'com/sunny/concurrent/volatilekey/VolatileSingleton'
  #           [sp+0x50]  (sp of caller)
  0x0000000002f40e00: mov    %eax,-0x6000(%rsp)
  0x0000000002f40e07: push   %rbp
  0x0000000002f40e08: sub    $0x40,%rsp         ;*synchronization entry
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@-1 (line 16)

  0x0000000002f40e0c: movabs $0xd6556ab8,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f40e16: mov    0x68(%r10),%r11d   ;*getstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@0 (line 16)

  0x0000000002f40e1a: test   %r11d,%r11d
  0x0000000002f40e1d: je     0x0000000002f40e3c  ;*ifnonnull
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@3 (line 16)

  0x0000000002f40e1f: movabs $0xd6556ab8,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f40e29: mov    0x68(%r10),%r10d
  0x0000000002f40e2d: mov    %r10,%rax          ;*getstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@37 (line 23)

  0x0000000002f40e30: add    $0x40,%rsp
  0x0000000002f40e34: pop    %rbp
  0x0000000002f40e35: test   %eax,-0x24e0e3b(%rip)        # 0x0000000000a60000
                                                ;   {poll_return}
  0x0000000002f40e3b: retq   
  0x0000000002f40e3c: mov    (%r10),%rax
  0x0000000002f40e3f: mov    %rax,%r10
  0x0000000002f40e42: and    $0x7,%r10
  0x0000000002f40e46: cmp    $0x5,%r10
  0x0000000002f40e4a: jne    0x0000000002f41011
  0x0000000002f40e50: mov    $0x200003df,%r11d  ;   {metadata('java/lang/Class')}
  0x0000000002f40e56: movabs $0x0,%r10
  0x0000000002f40e60: lea    (%r10,%r11,8),%r10
  0x0000000002f40e64: mov    0xa8(%r10),%r10
  0x0000000002f40e6b: mov    %r10,%r11
  0x0000000002f40e6e: or     %r15,%r11
  0x0000000002f40e71: mov    %r11,%r8
  0x0000000002f40e74: xor    %rax,%r8
  0x0000000002f40e77: test   $0xffffffffffffff87,%r8
  0x0000000002f40e7e: jne    0x0000000002f41089  ;*monitorenter
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@10 (line 17)

  0x0000000002f40e84: movabs $0xd6556ab8,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f40e8e: mov    0x68(%r10),%r10d   ;*getstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@11 (line 18)

  0x0000000002f40e92: mov    $0x7,%ebp
  0x0000000002f40e97: test   %r10d,%r10d
  0x0000000002f40e9a: je     0x0000000002f40f6e  ;*monitorexit
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@28 (line 21)

  0x0000000002f40ea0: movabs $0xd6556ab8,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f40eaa: and    (%r10),%rbp
  0x0000000002f40ead: cmp    $0x5,%rbp
  0x0000000002f40eb1: je     0x0000000002f40e1f
  0x0000000002f40eb7: movabs $0xd6556ab8,%r11   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f40ec1: lea    0x30(%rsp),%rax
  0x0000000002f40ec6: cmpq   $0x0,(%rax)
  0x0000000002f40ecd: je     0x0000000002f40f47
  0x0000000002f40ed3: mov    (%r11),%r10
  0x0000000002f40ed6: test   $0x2,%r10
  0x0000000002f40edd: je     0x0000000002f40f3f
  0x0000000002f40edf: mov    0x16(%r10),%rax
  0x0000000002f40ee3: xor    %r15,%rax
  0x0000000002f40ee6: or     0x26(%r10),%rax
  0x0000000002f40eea: jne    0x0000000002f40f47
  0x0000000002f40eec: mov    0x36(%r10),%rax
  0x0000000002f40ef0: or     0x3e(%r10),%rax
  0x0000000002f40ef4: jne    0x0000000002f40f00
  0x0000000002f40ef6: movq   $0x0,0x16(%r10)
  0x0000000002f40efe: jmp    0x0000000002f40f47
  0x0000000002f40f00: cmpq   $0x0,0x46(%r10)
  0x0000000002f40f08: je     0x0000000002f40f33
  0x0000000002f40f0a: movq   $0x0,0x16(%r10)
  0x0000000002f40f12: lock addl $0x0,(%rsp)
  0x0000000002f40f17: cmpq   $0x0,0x46(%r10)
  0x0000000002f40f1f: jne    0x0000000002f40f38
  0x0000000002f40f21: movabs $0x0,%rax
  0x0000000002f40f2b: lock cmpxchg %r15,0x16(%r10)
  0x0000000002f40f31: jne    0x0000000002f40f38
  0x0000000002f40f33: or     $0x1,%eax
  0x0000000002f40f36: jmp    0x0000000002f40f47
  0x0000000002f40f38: test   $0x0,%eax
  0x0000000002f40f3d: jmp    0x0000000002f40f47
  0x0000000002f40f3f: mov    (%rax),%r10
  0x0000000002f40f42: lock cmpxchg %r10,(%r11)
  0x0000000002f40f47: je     0x0000000002f40e1f
  0x0000000002f40f4d: movabs $0xd6556ab8,%rcx   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f40f57: lea    0x30(%rsp),%rdx    ;*monitorenter
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@10 (line 17)

  0x0000000002f40f5c: movabs $0x650fcce0,%r10
  0x0000000002f40f66: callq  *%r10              ;*monitorexit
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@28 (line 21)

  0x0000000002f40f69: jmpq   0x0000000002f40e1f
  0x0000000002f40f6e: mov    0x60(%r15),%rax
  0x0000000002f40f72: mov    %rax,%r10
  0x0000000002f40f75: add    $0x10,%r10
  0x0000000002f40f79: cmp    0x70(%r15),%r10
  0x0000000002f40f7d: jae    0x0000000002f40ff1
  0x0000000002f40f7f: mov    %r10,0x60(%r15)
  0x0000000002f40f83: prefetchw 0xc0(%r10)
  0x0000000002f40f8b: mov    $0x2000c105,%r10d  ;   {metadata('com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f40f91: shl    $0x3,%r10
  0x0000000002f40f95: mov    0xa8(%r10),%r10
  0x0000000002f40f9c: mov    %r10,(%rax)
  0x0000000002f40f9f: movl   $0x2000c105,0x8(%rax)  ;   {metadata('com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f40fa6: mov    %r12d,0xc(%rax)
  0x0000000002f40faa: mov    %rax,%r10
  0x0000000002f40fad: mov    %r10,0x20(%rsp)    ;*new  ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@17 (line 19)

  0x0000000002f40fb2: mov    %r10,%rdx
  0x0000000002f40fb5: xchg   %ax,%ax
  0x0000000002f40fb7: callq  0x0000000002e761a0  ; OopMap{[32]=Oop off=444}
                                                ;*invokespecial <init>
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@21 (line 19)
                                                ;   {optimized virtual_call}
  0x0000000002f40fbc: mov    0x20(%rsp),%r10
  0x0000000002f40fc1: movabs $0xd6556ab8,%r11   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f40fcb: mov    %r10d,0x68(%r11)
  0x0000000002f40fcf: movabs $0xd6556ab8,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f40fd9: shr    $0x9,%r10
  0x0000000002f40fdd: mov    $0x11dde000,%r11d
  0x0000000002f40fe3: mov    %r12b,(%r11,%r10,1)
  0x0000000002f40fe7: lock addl $0x0,(%rsp)     ;*putstatic instance
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@24 (line 19)

  0x0000000002f40fec: jmpq   0x0000000002f40ea0
  0x0000000002f40ff1: movabs $0x100060828,%rdx  ;   {metadata('com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f40ffb: callq  0x0000000002e9f3e0  ; OopMap{off=512}
                                                ;*new  ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@17 (line 19)
                                                ;   {runtime_call}
  0x0000000002f41000: jmp    0x0000000002f40faa
  0x0000000002f41002: movabs $0xd6556ab8,%r11   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f4100c: lock cmpxchg %r10,(%r11)
  0x0000000002f41011: movabs $0xd6556ab8,%r11   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f4101b: lea    0x30(%rsp),%rbx
  0x0000000002f41020: mov    (%r11),%rax
  0x0000000002f41023: test   $0x2,%rax
  0x0000000002f41029: jne    0x0000000002f4104f
  0x0000000002f4102b: or     $0x1,%rax
  0x0000000002f4102f: mov    %rax,(%rbx)
  0x0000000002f41032: lock cmpxchg %rbx,(%r11)
  0x0000000002f41037: je     0x0000000002f41068
  0x0000000002f4103d: sub    %rsp,%rax
  0x0000000002f41040: and    $0xfffffffffffff007,%rax
  0x0000000002f41047: mov    %rax,(%rbx)
  0x0000000002f4104a: jmpq   0x0000000002f41068
  0x0000000002f4104f: movq   $0x3,(%rbx)
  0x0000000002f41056: mov    %rax,%rbx
  0x0000000002f41059: mov    0x16(%rbx),%rax
  0x0000000002f4105d: test   %rax,%rax
  0x0000000002f41060: jne    0x0000000002f41068
  0x0000000002f41062: lock cmpxchg %r15,0x16(%rbx)
  0x0000000002f41068: je     0x0000000002f40e84
  0x0000000002f4106e: movabs $0xd6556ab8,%rdx   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f41078: lea    0x30(%rsp),%r8
  0x0000000002f4107d: xchg   %ax,%ax
  0x0000000002f4107f: callq  0x0000000002ea0160  ; OopMap{off=644}
                                                ;*monitorenter
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@10 (line 17)
                                                ;   {runtime_call}
  0x0000000002f41084: jmpq   0x0000000002f40e84
  0x0000000002f41089: test   $0x7,%r8
  0x0000000002f41090: jne    0x0000000002f41002
  0x0000000002f41096: test   $0x300,%r8
  0x0000000002f4109d: jne    0x0000000002f410ac
  0x0000000002f4109f: and    $0x37f,%rax
  0x0000000002f410a6: mov    %rax,%r11
  0x0000000002f410a9: or     %r15,%r11
  0x0000000002f410ac: movabs $0xd6556ab8,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f410b6: lock cmpxchg %r11,(%r10)
  0x0000000002f410bb: jne    0x0000000002f4106e
  0x0000000002f410bd: jmpq   0x0000000002f40e84  ;*new
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@17 (line 19)

  0x0000000002f410c2: mov    %rax,%rbx
  0x0000000002f410c5: jmp    0x0000000002f410ca  ;*invokespecial <init>
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@21 (line 19)

  0x0000000002f410c7: mov    %rax,%rbx
  0x0000000002f410ca: movabs $0xd6556ab8,%r10   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f410d4: and    (%r10),%rbp
  0x0000000002f410d7: cmp    $0x5,%rbp
  0x0000000002f410db: jne    0x0000000002f410ea  ;*monitorexit
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@34 (line 21)

  0x0000000002f410dd: mov    %rbx,%rdx
  0x0000000002f410e0: add    $0x40,%rsp
  0x0000000002f410e4: pop    %rbp
  0x0000000002f410e5: jmpq   0x0000000002ea0060  ;   {runtime_call}
  0x0000000002f410ea: movabs $0xd6556ab8,%r11   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f410f4: lea    0x30(%rsp),%rax
  0x0000000002f410f9: cmpq   $0x0,(%rax)
  0x0000000002f41100: je     0x0000000002f4117a
  0x0000000002f41106: mov    (%r11),%r10
  0x0000000002f41109: test   $0x2,%r10
  0x0000000002f41110: je     0x0000000002f41172
  0x0000000002f41112: mov    0x16(%r10),%rax
  0x0000000002f41116: xor    %r15,%rax
  0x0000000002f41119: or     0x26(%r10),%rax
  0x0000000002f4111d: jne    0x0000000002f4117a
  0x0000000002f4111f: mov    0x36(%r10),%rax
  0x0000000002f41123: or     0x3e(%r10),%rax
  0x0000000002f41127: jne    0x0000000002f41133
  0x0000000002f41129: movq   $0x0,0x16(%r10)
  0x0000000002f41131: jmp    0x0000000002f4117a
  0x0000000002f41133: cmpq   $0x0,0x46(%r10)
  0x0000000002f4113b: je     0x0000000002f41166
  0x0000000002f4113d: movq   $0x0,0x16(%r10)
  0x0000000002f41145: lock addl $0x0,(%rsp)
  0x0000000002f4114a: cmpq   $0x0,0x46(%r10)
  0x0000000002f41152: jne    0x0000000002f4116b
  0x0000000002f41154: movabs $0x0,%rax
  0x0000000002f4115e: lock cmpxchg %r15,0x16(%r10)
  0x0000000002f41164: jne    0x0000000002f4116b
  0x0000000002f41166: or     $0x1,%eax
  0x0000000002f41169: jmp    0x0000000002f4117a
  0x0000000002f4116b: test   $0x0,%eax
  0x0000000002f41170: jmp    0x0000000002f4117a
  0x0000000002f41172: mov    (%rax),%r10
  0x0000000002f41175: lock cmpxchg %r10,(%r11)
  0x0000000002f4117a: je     0x0000000002f410dd
  0x0000000002f41180: movabs $0xd6556ab8,%rcx   ;   {oop(a 'java/lang/Class' = 'com/sunny/concurrent/volatilekey/VolatileSingleton')}
  0x0000000002f4118a: lea    0x30(%rsp),%rdx    ;*monitorenter
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@10 (line 17)

  0x0000000002f4118f: movabs $0x650fcce0,%r10
  0x0000000002f41199: callq  *%r10              ;*monitorexit
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@34 (line 21)

  0x0000000002f4119c: jmpq   0x0000000002f410dd  ;*monitorexit
                                                ; - com.sunny.concurrent.volatilekey.VolatileSingleton::getInstance@28 (line 21)

 
[Stub Code]
  0x0000000002f411c0: movabs $0x0,%rbx          ;   {no_reloc}
  0x0000000002f411ca: jmpq   0x0000000002f411ca  ;   {runtime_call}
[Exception Handler]
  0x0000000002f411cf: jmpq   0x0000000002e9f4a0  ;   {runtime_call}
[Deopt Handler Code]
  0x0000000002f411d4: callq  0x0000000002f411d9
  0x0000000002f411d9: subq   $0x5,(%rsp)
  0x0000000002f411de: jmpq   0x0000000002e77600  ;   {runtime_call}
  0x0000000002f411e3: hlt    
  0x0000000002f411e4: hlt    
  0x0000000002f411e5: hlt    
  0x0000000002f411e6: hlt    
  0x0000000002f411e7: hlt    
Java HotSpot(TM) 64-Bit Server VM warning: PrintAssembly is enabled; turning on DebugNonSafepoints to gain additional output

Process finished with exit code 0

?使用文本比較器進(jìn)行對(duì)比捐祠,我們便可以知道帶volatile關(guān)鍵字和不帶的差異:帶了volatile關(guān)鍵字匯編指令會(huì)比不帶volatile關(guān)鍵多了lock addl $0x0,(%rsp)操作;


?這個(gè)操作相當(dāng)于一個(gè)內(nèi)存屏障桑李,只有一個(gè) CPU 訪問(wèn)內(nèi)存時(shí)踱蛀,并不需要內(nèi)存屏障窿给;但如果有兩個(gè)或更多 CPU 訪問(wèn)同一塊內(nèi)存,且其中有一個(gè)在觀測(cè)另一個(gè)率拒,就需要內(nèi)存屏障來(lái)保證一致性了崩泡。指令lock addl $0x0,(%esp)顯然是一個(gè)空操作,關(guān)鍵在于 lock 前綴猬膨,查詢 IA32 手冊(cè)角撞,它的作用是使得本 CPU 的 Cache 寫入了內(nèi)存,該寫入動(dòng)作也會(huì)引起別的 CPU invalidate 其 Cache勃痴。所以通過(guò)這樣一個(gè)空操作谒所,可讓前面 volatile 變量的修改對(duì)其他 CPU 立即可見(jiàn)。
Lock指令

聲言處理器的 LOCK# 信號(hào)(使指令成為原子指令)沛申。在多處理器環(huán)境中劣领,LOCK# 信號(hào)確保在聲言該信號(hào)期間,處理器可以獨(dú)占使用任何共享內(nèi)存铁材。
請(qǐng)注意尖淘,在后期的“英特爾(R) 體系結(jié)構(gòu)”處理器(如奔騰? Pro 處理器)中,鎖定可能會(huì)在沒(méi)有聲言 LOCK# 信號(hào)的情況下發(fā)生著觉。請(qǐng)參閱下面的“英特爾(R) 體系結(jié)構(gòu)兼容性”村生。
LOCK 前綴只能用在以下指令的前面,并且僅限使用內(nèi)存操作數(shù)形式的這些指令:ADD饼丘、ADC梆造、AND、BTC葬毫、BTR镇辉、BTS、CMPXCHG贴捡、DEC忽肛、INC、NEG烂斋、NOT屹逛、OR、SBB汛骂、SUB罕模、XOR、XADD 及 XCHG帘瞭。如果同其它任何指令一起使用 LOCK 前綴淑掌,則生成操作碼未定義異常。不論是否使用 LOCK 前綴蝶念,XCHG 指令總是聲言 LOCK# 信號(hào)抛腕。
LOCK 前綴通常同 BTS 指令一起使用芋绸,以便在共享內(nèi)存環(huán)境中讀取-修改-寫入內(nèi)存位置。
內(nèi)存字段是否對(duì)齊不影響 LOCK 前綴的完整性担敌。對(duì)于雜亂的未對(duì)齊字段摔敛,會(huì)遵循內(nèi)存鎖定規(guī)則。

五全封、參考引用

  1. 汪文君《Java高并發(fā)編程詳解多線程與架構(gòu)設(shè)計(jì)》
  2. 《并發(fā)研究之CPU緩存一致性協(xié)議(MESI)》
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末马昙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刹悴,更是在濱河造成了極大的恐慌行楞,老刑警劉巖诡曙,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異集歇,居然都是意外死亡甚淡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門捧请,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事钓丰。” “怎么了每币?”我有些...
    開(kāi)封第一講書人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵携丁,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我兰怠,道長(zhǎng)梦鉴,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任揭保,我火速辦了婚禮肥橙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘秸侣。我一直安慰自己存筏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布味榛。 她就那樣靜靜地躺著椭坚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪搏色。 梳的紋絲不亂的頭發(fā)上善茎,一...
    開(kāi)封第一講書人閱讀 49,792評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音频轿,去河邊找鬼巾表。 笑死汁掠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的集币。 我是一名探鬼主播考阱,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鞠苟!你這毒婦竟也來(lái)了乞榨?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤当娱,失蹤者是張志新(化名)和其女友劉穎吃既,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體跨细,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹦倚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冀惭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片震叙。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖散休,靈堂內(nèi)的尸體忽然破棺而出媒楼,到底是詐尸還是另有隱情,我是刑警寧澤戚丸,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布划址,位于F島的核電站,受9級(jí)特大地震影響限府,放射性物質(zhì)發(fā)生泄漏夺颤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一胁勺、第九天 我趴在偏房一處隱蔽的房頂上張望世澜。 院中可真熱鬧,春花似錦姻几、人聲如沸宜狐。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)抚恒。三九已至,卻和暖如春络拌,著一層夾襖步出監(jiān)牢的瞬間俭驮,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留混萝,地道東北人遗遵。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像逸嘀,于是被迫代替她去往敵國(guó)和親车要。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容