2013-11-04 11 views
6

. Hiçbir şey bulamadım. Aşağıdaki kod var:Java, bu son derece açık veya başka bir yerde yanıtlanmışsa üzgünüz karışıklık

public class SimpleThread extends Thread { 
    public static Integer sharedVal = 0; 
    public SimpleThread() { 

    } 
    @Override 
    public void run() { 
     while(true) {   
      iterator(); 
     } 
    } 

    public void theSleeper() { 
     System.out.println("Thread: " + this.getId() + " is going to sleep!"); 
     try { 
      this.sleep(5000); 
     } catch(Exception e) { 

     } 
    } 

    public void iterator() { 
     synchronized(sharedVal) { 
      System.out.println("Iterating sharedVal in thread: " + this.getId()); 
      sharedVal++; 
      System.out.println(sharedVal); 
      theSleeper(); 
      System.out.println("Thread : " + getId() + " is done sleeping, trying to iterate again..."); 
     } 
    } 
} 

Bu SimpleThread sınıfının iki örneğini oluşturmak ve çalıştırmak yöntemlerini yürütmek. Ben gibi bir şey görmeyi umuyoruz: Konu 9 artan ... Konu 9 uyku ... (5 saniye sonra) Konu 10 artım .... Konu 10 uyku .... Bunu bekliyorum çünkü yineleyici yöntemini kilitliyorum, böylece bir kerede yalnızca bir iş parçacığı girebilmeli. Bunun yerine, her iki iş parçacığının artması ve ardından her ikisinin de 5 saniye beklemesidir. Bu sonsuza dek tekrarlanır. Burada beklenen davranışa sahip olmak için neyi özlüyorum? Çok teşekkürler!

DÜZENLEME: Yeni bir genel statik değişken oluşturdum: public static Nesne theLock = new Object(). Şimdi, yineleyici yönteminde, senkronize (TheLock) yapıyorum. Çıkış beklediğimden daha fazla, çünkü kilit asla değişmiyor. Ancak, şimdi sadece iplik 9, yönteme giriyor. Görünüşe göre, iplik 10 açlıktan ölüyor ve asla bir dönüş yapmıyor. Bu garip görünüyor. Sadece birkaç kez değil, her zaman sadece iplik 9 tekrarlanıyor ve uyuyor. 9, 10, 9, 10 olacağını düşünürdüm. Veya belki de 9, 10, 10, 10, 9, 10, 9, 9, 10, vb. Gibi rasgele bir dağılım.

EDIT2: Ne olduğunu görüyorum. Şimdi oluyor. 9. parçanın kilidi var. İş parçacığı 10, işleve girmeye çalışır, ancak hemen beklemek söylenir. İşlev tamamlandıktan sonra, hala iş parçacığı 9s olabilir. Iş parçacığı 9 daha sonra kilidi siler ve döngü devam eder. Bir dönüş almak için iş parçacığı 10 için zamanlama penceresi çok küçüktür ve bir dönüş alsaydı muhtemelen açlıktan 9 olurdu. Bu söyleniyor, iterator() içinde senkronize blok sonra verim() koyarak daha fazla yapmak için görünmüyor adil. Metod hakkındaki yorumları okudum ve programlayıcı aslında getiri() görmezden gelebilir.

+3

Autoboxing şeytan –

+0

Hahaha olduğunu, bunun sorunlu olabilir görünüyor! :) – user2045279

cevap

3

Sorununuz burada bulunduğu

senkronize (SympleThread.class): Bunun yerine senkronizasyonu için aşağıdaki ifadeyi kullanabilirsiniz nedeniyle Autoboxing için, bu çizgi

sharedVal++; 

bu çevirir:

sharedVal = Integer.valueOf(sharedVal.intValue() + 1); 

, her çalıştırıldığında yeni bir 10 nesnesi oluşturur, böylece her seferinde synchronized bloğunun izlediği zaman, kilitlenir. farklı bir değer.

private final static Object LOCK = new Object(); 

ve sonra yerine synchronized (LOCK) {... kullanmak için senkronizasyon değiştirin:

eşitlemek için özel bir nesne kullanın.

(Ayrıca kilitlemek için getClass() kullanabilirsiniz, ama ben şahsen kamu dünyaya kilit nesneleri göstermek için sevmiyorum)

+0

Evet bakın, benim gıcırtılıma işaret için teşekkür ederiz. Lütfen düzenlememe bakın, teşekkürler! – user2045279

+0

İplik 9 uykusundan geri döndüğünde, kilidi serbest bırakır ve sonra tekrar kazanmaz ve 10'u hiçbir olasılıkla bırakmaz. Tek şansı, programlayıcı iplik 9 ilikli kilitleri durdurmasıdır, bu da olası değildir. İterasyonlar arasında bir 'Thread.yield()' ekleyin, bu da işleri biraz daha adil hale getirecektir. – Darkhogg

+0

Evet, şimdi bunu görüyorum ve bunu ikinci düzenlememe ekledim. Thread.yield(), programlayıcı büyük olasılıkla göz ardı ettiği için çok yardımcı görünmüyor. Bu söyleniyor, sanırım şimdi daha çok anlıyorum. Çok teşekkürler! – user2045279

5

Arttırma yaparken, yeni bir tamsayı örneği ve kilitleme için yeni bir nesne oluşturursunuz.

+0

^- - - - bu. – MadConan

+1

@OP: StringBuilder (StringBuffer senkronize olduğundan beri StringBuffer değil.) Gibi değişebilir bir şey kullanarak tekrar deneyin. – MadConan

+0

Tamamen katılıyorum ve aptal hissediyorum. Tamsayı'nın neden değişmez olduğunu bilmiyorum, ama bu başka bir sorun. Lütfen düzenlememe bakın. – user2045279

1

Etkili ipler her yinelemesini kullandığınız kilit değişiyor: ++ tamsayı yeni bir örneğini oluşturur üzerinde (Tamsayı sınıfı değişmez)

+0

Evet, bir diğeri de, bu hatayı işaret ettiğin için teşekkürler. Lütfen benim düzenleme – user2045279

0

sharedVal üyesi varible örneği Eğer ++ sharedVal gerçekleştirdiğinizde değişiyor.