一翘鸭、摘要
?在《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ò)程如下。
- 讀取主內(nèi)存的i到CPU Cache中工闺。
- 對(duì)i進(jìn)行加1操作乍赫。
- 將結(jié)果協(xié)會(huì)到CPU Cache中。
- 將數(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)行如下操作:
- 讀取操作伙窃,不做任何處理菩颖,只是將Cache中的數(shù)據(jù)讀取到寄存器。
- 寫入操作对供,發(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ī)則定義),其步驟具體如下:
- Reader線程從主內(nèi)存中獲取init_value的值為0都办,并且將其緩存到本地工作內(nèi)存中掂之。
- Updater線程將init_value的值在本地工作內(nèi)存中修飾為1,然后立即刷新至主內(nèi)存中脆丁。
- Reader線程在本地工作內(nèi)存中的init_value失效(反映到硬件上就是CPU的L1或者L2的Cache Line失效)世舰。
- 由于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í)也是由三步組成的,具體如下:
- 從主內(nèi)存中獲取i的值谱秽,然后緩存至線程工作內(nèi)存中洽蛀。
- 在線程工作內(nèi)存中為i進(jìn)行加1的操作摹迷。
- 將i的最新值寫入主內(nèi)存中。
?上面的操作單獨(dú)的每一個(gè)操作都是原子性操作郊供,但是合起來(lái)就不是峡碉,因?yàn)樵趫?zhí)行中途很有可能會(huì)被其他線程打斷,例如如下操作情況颂碘。
- 假設(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)峡竣。
- 線程B同樣需要從主內(nèi)存中讀取i的值,由于線程A沒(méi)有對(duì)i做過(guò)任何修改操作量九,因此此時(shí)B獲取到的i仍然是100.
- 線程B工作內(nèi)存中為i執(zhí)行了加1操作适掰,但是未刷新至主內(nèi)存中。
- 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ì)被失效肌似。
- 線程A將i=101寫入主內(nèi)存之中费就。
- 線程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# 信號(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ī)則。
五全封、參考引用
- 汪文君《Java高并發(fā)編程詳解多線程與架構(gòu)設(shè)計(jì)》
- 《并發(fā)研究之CPU緩存一致性協(xié)議(MESI)》