Di Intel, pembacaan volatile yang tidak bisa dibantah cukup murah. Jika kita mempertimbangkan kasus sederhana berikut:
public static long l;
public static void run() {
if (l == -1)
System.exit(-1);
if (l == -2)
System.exit(-1);
}
Menggunakan kemampuan Java 7 untuk mencetak kode assembly, metode run terlihat seperti ini:
# {method} 'run2' '()V' in 'Test2'
# [sp+0x10] (sp of caller)
0xb396ce80: mov %eax,-0x3000(%esp)
0xb396ce87: push %ebp
0xb396ce88: sub $0x8,%esp ;*synchronization entry
; - Test2::run2@-1 (line 33)
0xb396ce8e: mov $0xffffffff,%ecx
0xb396ce93: mov $0xffffffff,%ebx
0xb396ce98: mov $0x6fa2b2f0,%esi ; {oop('Test2')}
0xb396ce9d: mov 0x150(%esi),%ebp
0xb396cea3: mov 0x154(%esi),%edi ;*getstatic l
; - Test2::run@0 (line 33)
0xb396cea9: cmp %ecx,%ebp
0xb396ceab: jne 0xb396ceaf
0xb396cead: cmp %ebx,%edi
0xb396ceaf: je 0xb396cece ;*getstatic l
; - Test2::run@14 (line 37)
0xb396ceb1: mov $0xfffffffe,%ecx
0xb396ceb6: mov $0xffffffff,%ebx
0xb396cebb: cmp %ecx,%ebp
0xb396cebd: jne 0xb396cec1
0xb396cebf: cmp %ebx,%edi
0xb396cec1: je 0xb396ceeb ;*return
; - Test2::run@28 (line 40)
0xb396cec3: add $0x8,%esp
0xb396cec6: pop %ebp
0xb396cec7: test %eax,0xb7732000 ; {poll_return}
;... lines removed
Jika Anda melihat 2 referensi untuk getstatic, yang pertama melibatkan beban dari memori, yang kedua melewatkan beban karena nilainya digunakan kembali dari register yang sudah dimuat ke dalamnya (panjangnya 64 bit dan di laptop 32 bit saya itu menggunakan 2 register).
Jika kita membuat variabel l mudah menguap, perakitan yang dihasilkan berbeda.
# {method} 'run2' '()V' in 'Test2'
# [sp+0x10] (sp of caller)
0xb3ab9340: mov %eax,-0x3000(%esp)
0xb3ab9347: push %ebp
0xb3ab9348: sub $0x8,%esp ;*synchronization entry
; - Test2::run2@-1 (line 32)
0xb3ab934e: mov $0xffffffff,%ecx
0xb3ab9353: mov $0xffffffff,%ebx
0xb3ab9358: mov $0x150,%ebp
0xb3ab935d: movsd 0x6fb7b2f0(%ebp),%xmm0 ; {oop('Test2')}
0xb3ab9365: movd %xmm0,%eax
0xb3ab9369: psrlq $0x20,%xmm0
0xb3ab936e: movd %xmm0,%edx ;*getstatic l
; - Test2::run@0 (line 32)
0xb3ab9372: cmp %ecx,%eax
0xb3ab9374: jne 0xb3ab9378
0xb3ab9376: cmp %ebx,%edx
0xb3ab9378: je 0xb3ab93ac
0xb3ab937a: mov $0xfffffffe,%ecx
0xb3ab937f: mov $0xffffffff,%ebx
0xb3ab9384: movsd 0x6fb7b2f0(%ebp),%xmm0 ; {oop('Test2')}
0xb3ab938c: movd %xmm0,%ebp
0xb3ab9390: psrlq $0x20,%xmm0
0xb3ab9395: movd %xmm0,%edi ;*getstatic l
; - Test2::run@14 (line 36)
0xb3ab9399: cmp %ecx,%ebp
0xb3ab939b: jne 0xb3ab939f
0xb3ab939d: cmp %ebx,%edi
0xb3ab939f: je 0xb3ab93ba ;*return
;... lines removed
Dalam hal ini, kedua referensi getstatic ke variabel l melibatkan beban dari memori, yaitu nilai tidak dapat disimpan dalam register di beberapa pembacaan volatil. Untuk memastikan bahwa ada atomic membaca nilai dibaca dari memori utama ke dalam register MMX movsd 0x6fb7b2f0(%ebp),%xmm0
membuat operasi baca instruksi tunggal (dari contoh sebelumnya kita melihat bahwa nilai 64bit biasanya membutuhkan dua 32bit membaca pada sistem 32bit).
Jadi biaya keseluruhan dari pembacaan volatil kira-kira akan setara dengan beban memori dan bisa semurah akses cache L1. Namun jika inti lain menulis ke variabel volatile, baris cache akan menjadi tidak valid sehingga membutuhkan memori utama atau mungkin akses cache L3. Biaya sebenarnya akan sangat bergantung pada arsitektur CPU. Bahkan antara Intel dan AMD, protokol koherensi cache berbeda.