這個問題是不是他們之間的區別 - 我知道虛假的失敗是什麼,爲什麼會發生在LL/SC。我的問題是如果我在intel x86上並使用java-9(build 149),爲什麼它們的彙編代碼有區別?weakCompareAndSwap VS比較並交換
public class WeakVsNonWeak {
static jdk.internal.misc.Unsafe UNSAFE = jdk.internal.misc.Unsafe.getUnsafe();
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
Holder h = new Holder();
h.setValue(33);
Class<?> holderClass = Holder.class;
long valueOffset = UNSAFE.objectFieldOffset(holderClass.getDeclaredField("value"));
int result = 0;
for (int i = 0; i < 30_000; ++i) {
result = strong(h, valueOffset);
}
System.out.println(result);
}
private static int strong(Holder h, long offset) {
int sum = 0;
for (int i = 33; i < 11_000; ++i) {
boolean result = UNSAFE.weakCompareAndSwapInt(h, offset, i, i + 1);
if (!result) {
sum++;
}
}
return sum;
}
public static class Holder {
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
}
與運行:
輸出compareAndSwapInt的java -XX:-TieredCompilation
-XX:CICompilerCount=1
-XX:+UnlockDiagnosticVMOptions
-XX:+PrintIntrinsics
-XX:+PrintAssembly
--add-opens java.base/jdk.internal.misc=ALL-UNNAMED
WeakVsNonWeak
(相關部分):
輸出的weakCompareAndSwapInt 0x0000000109f0f4b8: movabs $0x111927c18,%rsi ; {metadata({method} {0x0000000111927c18} 'compareAndSwapInt' '(Ljava/lang/Object;JII)Z' in 'jdk/internal/misc/Unsafe')}
0x0000000109f0f4c2: mov %r15,%rdi
0x0000000109f0f4c5: test $0xf,%esp
0x0000000109f0f4cb: je 0x0000000109f0f4e3
0x0000000109f0f4d1: sub $0x8,%rsp
0x0000000109f0f4d5: callq 0x00000001098569d2 ; {runtime_call SharedRuntime::dtrace_method_entry(JavaThread*, Method*)}
0x0000000109f0f4da: add $0x8,%rsp
0x0000000109f0f4de: jmpq 0x0000000109f0f4e8
0x0000000109f0f4e3: callq 0x00000001098569d2 ; {runtime_call SharedRuntime::dtrace_method_entry(JavaThread*, Method*)}
0x0000000109f0f4e8: pop %r9
0x0000000109f0f4ea: pop %r8
0x0000000109f0f4ec: pop %rcx
0x0000000109f0f4ed: pop %rdx
0x0000000109f0f4ee: pop %rsi
0x0000000109f0f4ef: lea 0x210(%r15),%rdi
0x0000000109f0f4f6: movl $0x4,0x288(%r15)
0x0000000109f0f501: callq 0x00000001098fee40 ; {runtime_call Unsafe_CompareAndSwapInt(JNIEnv_*, _jobject*, _jobject*, long, int, int)}
0x0000000109f0f506: vzeroupper
0x0000000109f0f509: and $0xff,%eax
0x0000000109f0f50f: setne %al
0x0000000109f0f512: movl $0x5,0x288(%r15)
0x0000000109f0f51d: lock addl $0x0,-0x40(%rsp)
0x0000000109f0f523: cmpl $0x0,-0x3f04dd(%rip) # 0x0000000109b1f050
:
0x000000010b698840: sub $0x18,%rsp
0x0000010b698847: mov %rbp,0x10(%rsp)
0x000000010b69884c: mov %r8d,%eax
0x000000010b69884f: lock cmpxchg %r9d,(%rdx,%rcx,1)
0x000000010b698855: sete %r11b
0x000000010b698859: movzbl %r11b,%r11d ;*invokevirtual compareAndSwapInt {reexecute=0 rethrow=0 return_oop=0}
; - jdk.internal.misc.Unsafe::[email protected] (line 1369)
我遠遠不夠的多才多藝,瞭解整個輸出,但絕對可以看到鎖ADDL和鎖CMPXCHG之間的差異。
編輯 彼得的回答讓我想到了。讓我們來看看比較並交換將是一個內在的呼叫:
-XX:+ PrintIntrinsics -XX:-PrintAssembly
@ 7 jdk.internal.misc.Unsafe::compareAndSwapInt (0 bytes) (intrinsic)
@ 20 jdk.internal.misc.Unsafe::weakCompareAndSwapInt (11 bytes) (intrinsic).
然後用/運行兩次的例子,而不:
-XX:DisableIntrinsic = _compareAndSwapInt
This is sor奇怪的T,輸出是完全一樣的(完全相同的指令),唯一的變化是與使內在我得到這樣的電話:
0x000000010c23e355: callq 0x00000001016569d2 ; {runtime_call SharedRuntime::dtrace_method_entry(JavaThread*, Method*)}
0x000000010c23e381: callq 0x00000001016fee40 ; {runtime_call Unsafe_CompareAndSwapInt(JNIEnv_*, _jobject*, _jobject*, long, int, int)}
和殘疾人:
0x00000001109322d5: callq 0x0000000105c569d2 ; {runtime_call _ZN13SharedRuntime19dtrace_method_entryEP10JavaThreadP6Method}
0x00000001109322e3: callq 0x0000000105c569d2 ; {runtime_call _ZN13SharedRuntime19dtrace_method_entryEP10JavaThreadP6Method}
這是相當有趣,不應該內在的代碼是不同的?
EDIT-2 the8472也有意義。
鎖ADDL是MFENCE一個替代品刷新StoreBuffer在x86,據我所知,它有知名度,而不是原子確實做。此條目之前對,就是:
0x00000001133db6f6: movl $0x4,0x288(%r15)
0x00000001133db701: callq 0x00000001060fee40 ; {runtime_call Unsafe_CompareAndSwapInt(JNIEnv_*, _jobject*, _jobject*, long, int, int)}
0x00000001133db706: vzeroupper
0x00000001133db709: and $0xff,%eax
0x00000001133db70f: setne %al
0x00000001133db712: movl $0x5,0x288(%r15)
0x00000001133db71d: lock addl $0x0,-0x40(%rsp)
0x00000001133db723: cmpl $0x0,-0xd0bc6dd(%rip) # 0x000000010631f050
; {external_word}
如果你看看here是將委託給另一本地call to Atomic:: cmpxchg這似乎是原子做掉。
爲什麼這不是直接替代鎖cmpxchg是我的一個謎。
與您的編輯和來自不同優化級別的衆多彙編樣本不太清楚你實際要求什麼。 – the8472
因此,'sun.misc.Unsafe'仍然沒有消失,但是移動到另一個包jdk.internal.misc中,證明它實際上不是一個兼容性問題,它使這個類保持活着? – Holger
@Holger它沒有移動,現在有兩個版本。正如Shipilev所說,sun.misc.Unsafe將被刪除 - 這次肯定。在sun.misc.Unsafe過去很有用的* other *地方有多個增強功能,現在已經過時(比如AtomicFieldUpdater)。他們甚至將釋放/獲取語義直接添加到不安全! – Eugene