SORU
16 Mayıs 2012, ÇARŞAMBA


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;
    }
}

bgerekira 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
16 Mayıs 2012, ÇARŞAMBA


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.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • bcbauer

    bcbauer

    7 ŞUBAT 2007
  • Charles Nesson

    Charles Ness

    27 NİSAN 2006
  • Māris Zaharovs

    Māris Zahar

    28 Mayıs 2008

İLGİLİ SORU / CEVAPLAR