Java 5'te neden uçucu değil't senkronize önbelleğe alınan ana bellek ile değişkenler kopyaları?
Göre:
http://www.ibm.com/developerworks/library/j-jtp03304/
Altında yeni bir bellek modeli, ne zaman iş parçacığı Bir yazar için geçici bir değişken V ve B iş parçacığı okur V, değişken değerleri olduğunu görünür Bir zaman V yazılmış garantilidir artık görünür olması için B
Ve internette birçok yerde aşağıdaki kodu asla baskı gereken devlet"": . hata
public class Test {
volatile static private int a;
static private int b;
public static void main(String [] args) throws Exception {
for (int i = 0; i < 100; i ) {
new Thread() {
@Override
public void run() {
int tt = b; // makes the jvm cache the value of b
while (a==0) {
}
if (b == 0) {
System.out.println("error");
}
}
}.start();
}
b = 1;
a = 1;
}
}
b
gerekira
1 olduğunda tüm iş parçacıkları için 1.
AncakBen bazen "" basılmış . hatası alıyorum . Bu nasıl mümkün olabilir?
CEVAP
Güncelleme:
İlgilenen herkes bu hata için ve Java 7u6 için ele düzeltildi inşa b14. Hata/rapor düzeltmeleri burada görebilirsiniz
Orijinal Cevap
Düşünmek gerekir/sipariş bellek görünürlük açısından düşünme onun olur-daha önce bir ilişki. b != 0
için önemli bir ön koşul a == 1
için. a != 1
eÄŸer b ya 1 ya da 0 olabilir.
Bir iş parçacığı iş parçacığı b == 1
garanti o a == 1
görünce.
Post OP örnekte 5, Java, b while(a == 0)
sonları 1 olması garanti edilir bir kez
Düzenleme:
Kat simülasyonu birçok numarayı araştırdım ve çıkış göremedim.
Ne işletim sistemi, Java sürüm ve CPU altında test ediyorsun?
Windows 7, 1.6_24 (_31 ile çalışan) Java kullanıyorum
Edit 2:
OP ve Walter Laan şeref - benim İçin sadece (ama dışarıda) 64 bit bir windows 7 32 bit için 64 bit Java Java değiştirdim, ne zaman oldu.
Edit 3:
tt
, b
ya da daha doğrusu staticget tayini önemli bir etkisi (int tt = b;
Kaldır kanıtlamak için ve her zaman işe yarar. var gibi görünüyor
tt
b
yük sonra coniditonal (bu değer referansı tt
) kullanılacak alanı yerel olarak saklar gibi görünüyor. Eğer öyleyse b == 0
doÄŸruysa muhtemelen tt
yerel maÄŸaza 0 (tt
yerel atamak 1 Bu noktada bir yarış) anlamına gelir. Bu yalnızca istemci seti ile 32 Bit Java için doğru 1.6 & 7 gibi görünüyor.
İki çıkış Meclisi ve burada olduğunu hemen fark karşılaştırdım. (Akla parçacıkları bu).
"" . Bu hata baskılı
0x021dd753: test êx,0x180100 ; {poll}
0x021dd759: cmp $0x0,ìx
0x021dd75c: je 0x021dd748 ;*ifeq
; - Test$1::run@7 (line 13)
0x021dd75e: cmp $0x0,íx
0x021dd761: jne 0x021dd788 ;*ifne
; - Test$1::run@13 (line 17)
0x021dd767: nop
0x021dd768: jmp 0x021dd7b8 ; {no_reloc}
0x021dd76d: xchg %ax,%ax
0x021dd770: jmp 0x021dd7d2 ; implicit exception: dispatches to 0x021dd7c2
0x021dd775: nop ;*getstatic out
; - Test$1::run@16 (line 18)
0x021dd776: cmp (ìx),êx ; implicit exception: dispatches to 0x021dd7dc
0x021dd778: mov $0x39239500,íx ;*invokevirtual println
Ve
Bu baskı değil"" . hata
0x0226d763: test êx,0x180100 ; {poll}
0x0226d769: cmp $0x0,íx
0x0226d76c: je 0x0226d758 ;*ifeq
; - Test$1::run@7 (line 13)
0x0226d76e: mov $0x341b77f8,íx ; {oop('Test')}
0x0226d773: mov 0x154(íx),íx ;*getstatic b
; - Test::access$0@0 (line 3)
; - Test$1::run@10 (line 17)
0x0226d779: cmp $0x0,íx
0x0226d77c: jne 0x0226d7a8 ;*ifne
; - Test$1::run@13 (line 17)
0x0226d782: nopw 0x0(êx,êx,1)
0x0226d788: jmp 0x0226d7ed ; {no_reloc}
0x0226d78d: xchg %ax,%ax
0x0226d790: jmp 0x0226d807 ; implicit exception: dispatches to 0x0226d7f7
0x0226d795: nop ;*getstatic out
; - Test$1::run@16 (line 18)
0x0226d796: cmp (ìx),êx ; implicit exception: dispatches to 0x0226d811
0x0226d798: mov $0x39239500,íx ;*invokevirtual println
Bu örnekte ilk giriş basılmış bir çalışma "hata ikincisi çok uzaktayken" olan yoktu.
İşçi çalıştırmak ve düzgün 0 test etmeden önce b
yüklü atanmış gibi görünüyor.
0x0226d76e: mov $0x341b77f8,íx ; {oop('Test')}
0x0226d773: mov 0x154(íx),íx ;*getstatic b
; - Test::access$0@0 (line 3)
; - Test$1::run@10 (line 17)
0x0226d779: cmp $0x0,íx
0x0226d77c: jne 0x0226d7a8 ;*ifne
; - Test$1::run@13 (line 17)
"Hata" íx
önbelleğe alınmış sürümü yüklü . yazdırılan koşarken
0x021dd75e: cmp $0x0,íx
0x021dd761: jne 0x021dd788 ;*ifne
; - Test$1::run@13 (line 17)
Çevirici ile daha fazla deneyime sahip olanlar tartmak:) lütfen
4 düzenleyin
Son düzenleme eşzamanlılık dev bir el gibi, olmadan ve test yaptım olmalıdır
int tt = b;
atama biraz daha fazla. Ben 1000 100 max artırmak bırakılır int tt = b
dahil olduğunda 100% hata oranı ve %0 şansınız var.