一、摘要
?在《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ù)刷新到主存當中,具體過程如下。
- 讀取主內(nèi)存的i到CPU Cache中。
- 對i進行加1操作。
- 將結(jié)果協(xié)會到CPU Cache中。
- 將數(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中也存在一個副本,那么進行如下操作:
- 讀取操作,不做任何處理,只是將Cache中的數(shù)據(jù)讀取到寄存器。
- 寫入操作,發(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ī)則定義),其步驟具體如下:
- 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)鍵字對順序性的保證就比較霸道一點,直接禁止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++的操作其實也是由三步組成的,具體如下:
- 從主內(nèi)存中獲取i的值,然后緩存至線程工作內(nèi)存中。
- 在線程工作內(nèi)存中為i進行加1的操作。
- 將i的最新值寫入主內(nèi)存中。
?上面的操作單獨的每一個操作都是原子性操作,但是合起來就不是,因為在執(zhí)行中途很有可能會被其他線程打斷,例如如下操作情況。
- 假設(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)。
- 線程B同樣需要從主內(nèi)存中讀取i的值,由于線程A沒有對i做過任何修改操作,因此此時B獲取到的i仍然是100.
- 線程B工作內(nèi)存中為i執(zhí)行了加1操作,但是未刷新至主內(nèi)存中。
- CPU時間片的調(diào)度又將執(zhí)行權(quán)給了線程A,A線程直接對工作線程中的100進行加1運行(因為A線程已經(jīng)從主內(nèi)存中讀取了i的值),由于B線程并未寫入i的最新值,因此A線程工作空間中的100不會被失效。
- 線程A將i=101寫入主內(nèi)存之中。
- 線程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# 信號(使指令成為原子指令)。在多處理器環(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ī)則。
五、參考引用
- 汪文君《Java高并發(fā)編程詳解多線程與架構(gòu)設(shè)計》
- 《并發(fā)研究之CPU緩存一致性協(xié)議(MESI)》