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

一、摘要

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


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

?我們從一個例子來解釋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();

        /**
         * 啟動一個Reader線程,當發(fā)現(xiàn)local_value和init_value不同時,則輸出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();

        /**
         * 啟動一個Updater線程,主要用于對init_value的修改,當localValue >= 5 時,則退出生命周期
         */
        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線程能夠來得及輸出變化內(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線程進入死循環(huán);也就是說Reader線程沒有感知到Updater線程對init_value變量的修改;接下來我們對init_value的定義做一下小小的改動,改成如下方式:

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

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


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

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

3.1 CPU Cache模型

?由于兩邊速度的嚴重不對等,通過傳統(tǒng)FSB直連內(nèi)存的訪問方式很明顯會導致CPU資源受到大量的限制,降低CPU整體的吞吐量,于是就有了在CPU和主內(nèi)存之間增加緩存的設(shè)計,現(xiàn)在的緩存數(shù)量都已經(jīng)增加到了3級,最靠近CPU的緩存稱為L1,然后依次是L2,L3和主內(nèi)存;如圖所示:



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



?L1、L2、L3級Cache出現(xiàn)是為了解決CPU直接訪問內(nèi)存效率低下問題的,程序在運行的過程中,會將運算所需的數(shù)據(jù)從主存復制一份到CPU Cache中,這樣CPU進行計算時就可以直接對CPU Cache中的數(shù)據(jù)進行讀取和寫入,當運算結(jié)束后,再將CPU Cache中最新數(shù)據(jù)刷新到主內(nèi)存中,CPU通過直接訪問Cache的方式替代直接訪問主存的方式極大地提高CPU的吞吐能力。

3.2 CPU 緩存一致性問題

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

  1. 讀取主內(nèi)存的i到CPU Cache中。
  2. 對i進行加1操作。
  3. 將結(jié)果協(xié)會到CPU Cache中。
  4. 將數(shù)據(jù)刷新到主內(nèi)存中。
    ?i++在單線程的情況下不會出現(xiàn)任何問題,但是在多線程情況下就會有問題,每個線程都有自己的工作內(nèi)存(本地內(nèi)存,對應CPU中的Cache),變量i會在多個線程的本地內(nèi)存中都存在一個副本。如果同時有兩個線程執(zhí)行i++操作,假設(shè)i的初始值為0,每一個線程都從主內(nèi)存中獲取i的值存入CPU Cache中,然后經(jīng)過計算再寫入主內(nèi)存中,很有可能i在經(jīng)過兩次自增之后結(jié)果還是1,這就是緩存不一問致性問題。
    ?為了解決緩存不一致性題,通常主流的解決方法有如下兩種:
  • 通過總線加鎖的方式。
  • 通過緩存一致性協(xié)議。
    ?第一種方式常見于早起的CPU當中,而且是一種悲觀的實現(xiàn)方式,CPU和其他組件的通信都是通過總線(數(shù)據(jù)總線,控制總線,地址總線)來進行的,如果采用總線加鎖的方式,則會阻塞其他CPU對其他組件的訪問,從而使得只有一個CPU(搶到總線鎖)能夠訪問這個變量的內(nèi)存。這種方式效率低下,所以就有了第二種通過緩存一致性協(xié)議的方式來解決不一致的問題。
    ?分析緩存一致性協(xié)議之前,我們來理解下緩存行,之前也簡單提到了緩存行的概念:
  • 緩存是分段(line)的,一個段對應一塊存儲空間,我們稱之為緩存行,它是CPU緩存中可分配的最小存儲單元,大小32字節(jié)、64字節(jié)、128字節(jié)不等,這與CPU架構(gòu)有關(guān),通常來說是64字節(jié)。當CPU看到一條讀取內(nèi)存指令時,它會把內(nèi)存地址傳遞給一級數(shù)據(jù)緩存,一級數(shù)據(jù)緩存檢查它是否有這個內(nèi)存地址對應的緩存段,如果沒有就把整個緩存段從內(nèi)存(或更高一級的緩存)中加載進來。注意,這里說的是一次加載整個緩存段,這個也是局部性原理。
    ?緩存一致性協(xié)議有多種,但是日常處理的大多數(shù)計算機設(shè)備都屬于“嗅探(snooping)”協(xié)議,它的基本思想是:
所有的內(nèi)存的傳輸都發(fā)生在一條共享的總線上,而所有的處理器都能看到這條總線:緩存本身是獨立的,但是內(nèi)存是共享資源,所有的內(nèi)存訪問都要經(jīng)過仲裁(同一個指令周期中,只有一個CPU緩存可以讀寫內(nèi)存)。 
CPU緩存不僅僅在做內(nèi)存?zhèn)鬏數(shù)臅r候才與總線打交道,而是不停在嗅探總線上發(fā)生的數(shù)據(jù)交換,跟蹤其他緩存在做什么。所以當一個緩存代表他所屬的處理器去讀寫內(nèi)存時,其他處理器都會得到通知,它們以此來使自己的緩存保持同步。只要某個處理器一寫內(nèi)存,其他處理器馬上知道這塊內(nèi)存在它們的緩存段中已失效。

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

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

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

狀態(tài) 描述 監(jiān)聽任務
M(Modified) 該Cache Line有效,數(shù)據(jù)被修改了,和內(nèi)存中的數(shù)據(jù)不一致,數(shù)據(jù)只存在于本Cache中 緩存行必須時刻監(jiān)聽所有試圖讀該緩存行相對就主存的操作,這種操作必須在緩存將該緩存行寫回主存并將狀態(tài)變成S(共享)狀態(tài)之前被延遲執(zhí)行。
E(Exclusive) 該Cache line有效,數(shù)據(jù)和內(nèi)存中的數(shù)據(jù)一致,數(shù)據(jù)只存在于本Cache中。 緩存行也必須監(jiān)聽其它緩存讀主存中該緩存行的操作,一旦有這種操作,該緩存行需要變成S(共享)狀態(tài)。
S(Shared) 該Cache line有效,數(shù)據(jù)和內(nèi)存中的數(shù)據(jù)一致,數(shù)據(jù)存在于很多Cache中。 緩存行也必須監(jiān)聽其它緩存使該緩存行無效或者獨享該緩存行的請求,并將該緩存行變成無效(Invalid)。
I(Invalid) 該Cache line無效。

?這里的I、S和M狀態(tài)已經(jīng)有了對應的概念:失效/未載入、干凈以及臟的緩存段。所以這里新的知識點只有E狀態(tài),代表獨占式訪問,這個狀態(tài)解決了"在我們開始修改某塊內(nèi)存之前,我們需要告訴其它處理器"這一問題:只有當緩存行處于E或者M狀態(tài)時,處理器才能去寫它,也就是說只有在這兩種狀態(tài)下,處理器是獨占這個緩存行的。當處理器想寫某個緩存行時,如果它沒有獨占權(quán),它必須先發(fā)送一條"我要獨占權(quán)"的請求給總線,這會通知其它處理器把它們擁有的同一緩存段的拷貝失效(如果有)。只有在獲得獨占權(quán)后,處理器才能開始修改數(shù)據(jù)----并且此時這個處理器知道,這個緩存行只有一份拷貝,在我自己的緩存里,所以不會有任何沖突。

?反之,如果有其它處理器想讀取這個緩存行(馬上能知道,因為一直在嗅探總線),獨占或已修改的緩存行必須先回到"共享"狀態(tài)。如果是已修改的緩存行,那么還要先把內(nèi)容回寫到內(nèi)存中。

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

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

?volatile修飾的實例變量或者類變量具備如下兩層語義:

  • 保證了不同線程之間對共享變量操作時的可見性,也就是說當一個線程修改volatile修飾的變量,另外一個線程會理解看到最新的值。
  • 禁止對指令進行重排序
4.1.1理解volatile保證可見性

?關(guān)于共享變量在多線程間的可見性,在VolatileFoo例子中已經(jīng)體現(xiàn)的非常透徹了,Updater線程對init_value變量的每一次更改都會使得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)鍵字對順序性的保證就比較霸道一點,直接禁止JVM和處理器對volatile關(guān)鍵字修飾的指令進行重排序,但是對于volatile前后無依賴關(guān)系的指令則可以隨便怎么排序,比如:

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

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

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

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

4.1.3理解volatile保不保證原子性

?我們也先來看一個例子:

/**
 * <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();
                }
                /**
                 * 使計數(shù)器減1
                 */
                latch.countDown();
            }).start();
        }
        // 等待所有的線程完成工作
        latch.await();
        System.out.println(i);
    }
}

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

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

?上面的操作單獨的每一個操作都是原子性操作,但是合起來就不是,因為在執(zhí)行中途很有可能會被其他線程打斷,例如如下操作情況。

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

4.2 volatile的原理和實現(xiàn)機制

?通過下面的例子,我們將從Java生成的匯編指令來解析帶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方法前,我們增加JVM參數(shù):

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

?其中,參數(shù) -Xcomp 是讓虛擬機以編譯模式執(zhí)行代碼,這樣代碼可以偷懶,不需要執(zhí)行足夠次數(shù)來預熱都能觸發(fā) JIT 編譯。兩個 -XX:CompileCommand 意思是讓編譯器不要內(nèi)聯(lián) getInstance() 并且只編譯 getInstance(),-XX:+PrintAssembly 就是輸出反匯編內(nèi)容。如果一切順利的話,控制臺會出現(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方法,控制臺打印如下信息:

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

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


?這個操作相當于一個內(nèi)存屏障,只有一個 CPU 訪問內(nèi)存時,并不需要內(nèi)存屏障;但如果有兩個或更多 CPU 訪問同一塊內(nèi)存,且其中有一個在觀測另一個,就需要內(nèi)存屏障來保證一致性了。指令lock addl $0x0,(%esp)顯然是一個空操作,關(guān)鍵在于 lock 前綴,查詢 IA32 手冊,它的作用是使得本 CPU 的 Cache 寫入了內(nèi)存,該寫入動作也會引起別的 CPU invalidate 其 Cache。所以通過這樣一個空操作,可讓前面 volatile 變量的修改對其他 CPU 立即可見。
Lock指令

聲言處理器的 LOCK# 信號(使指令成為原子指令)。在多處理器環(huán)境中,LOCK# 信號確保在聲言該信號期間,處理器可以獨占使用任何共享內(nèi)存。
請注意,在后期的“英特爾(R) 體系結(jié)構(gòu)”處理器(如奔騰? Pro 處理器)中,鎖定可能會在沒有聲言 LOCK# 信號的情況下發(fā)生。請參閱下面的“英特爾(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# 信號。
LOCK 前綴通常同 BTS 指令一起使用,以便在共享內(nèi)存環(huán)境中讀取-修改-寫入內(nèi)存位置。
內(nèi)存字段是否對齊不影響 LOCK 前綴的完整性。對于雜亂的未對齊字段,會遵循內(nèi)存鎖定規(guī)則。

五、參考引用

  1. 汪文君《Java高并發(fā)編程詳解多線程與架構(gòu)設(shè)計》
  2. 《并發(fā)研究之CPU緩存一致性協(xié)議(MESI)》
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容