2016-04-12 9 views
1

Bir Tamsayı değişkeni alıyorum ve iki iş parçacığıyla paylaşıyorum. Bir iş parçacığı, sayıları bile yazdırmalı ve bir iş parçacığı tek sayıyı sıralı olarak yazmalıdır. Ancak NotlegalMonitorStateException öğesini atarak notify().java bekle ve bildir

package mywaitnotifytest; 
public class App { 

    public static void main(String[] args) { 
     Integer i=0; 
     Even even = new Even(i); 
     even.setName("EvenThread"); 
     Odd odd = new Odd(i); 
     odd.setName("OddThread"); 
     even.start(); 
     odd.start(); 
    } 
} 

class Even extends Thread{ 

    Integer var; 

    Even(Integer var){ 
     this.var=var; 
    } 

    @Override 
    public void run() { 
     while(true){ 
      synchronized (var) { 
       if(var%2==0){ 
        try { 
         var.wait(); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
       var++; 
       System.out.println(Thread.currentThread().getName()+" "+var); 
       var.notify(); 
      } 
     } 

    } 
} 

class Odd extends Thread{ 

    Integer var; 

    Odd(Integer var){ 
     this.var=var; 
    } 

    @Override 
    public void run() { 
     while(true){ 
      synchronized (var) { 
       if(var%2!=0){ 
        try { 
         var.wait(); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
       var++; 
       System.out.println(Thread.currentThread().getName()+" "+var); 
       var.notify(); 
      } 
     } 
    } 
} 

Ve çıktısı:

OddThread 1

Exception in thread "OddThread" java.lang.IllegalMonitorStateException 

at java.lang.Object.notify(Native Method) 

at mywaitnotifytest.Odd.run(App.java:67) 
+0

Bu soru farklı görünüyor. Ayrıca istisnanın sebebi oldukça farklıdır ve 'senkronize olmayan 'kod – ortis

+0

ile ilgisi yoktur. Kilitlendiğiniz nesneye' notify() 'demiyorsunuz. Kısacası, değişken bir alanı kilitlemeyin. Değiştirdiğinizde değiştirirsiniz. Ayrıca, havuzlanmış bir nesneye kilitlenmeyin, çünkü 'Tamsayı' bunun kafa karıştırıcı sonuçları olacağından. –

+0

Bekleyin ve senkronize edilmiş bloktan yalnızca –

cevap

3

Bunu bir tane daha alışılmış cevap yeterince farklı olduğunu düşünüyorum.

Bu durumda synchronized kullanıyorsunuz. Bir kilidi uyguladığınızda, bir referans değildir.


synchronized (var) { 

Bu nesneyi değil bir alan olarak var üzerinde var referanslar kilitler.


var++; 

Bu, nesne var sayı yerine geçer. Integer ve gerçekten de ilkel sarma iletmenin: Bu

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

Not aynıdır. Onlarda herhangi bir işlem gerçekleştirdiğinizde, aslında ilkel değeri kullanarak hesaplamayı ve nesneyi yeniden kutellemenizi engelliyorsunuz. Havuzlanmışsa aynı nesneyi geri almak mümkündür. Örneğin.

Integer i = 10; 
i += 0; // gives back the same object. 

Ancak, nesne

Double d = 10; 
d += 0; // creates a new object. 

var.notify(); 

girişimleri yeni bir nesne ile ilgili arama notify değil, kilitli bir

toplanmış değilse. Değiştirdiğiniz alanı kilitlemeye çalışmamalısınız. Göründüğü gibi yapmaz. Ayrıca havuzlanmış bir nesneyi kilitlememelisiniz. Bu durumda, ilgisiz bir amaç için aynı Integer kullanarak başka bir iş parçacığınız olabilir ve notify() alakasız bir iş parçacığı uyandıracak.

doğru bildirmek/bekleme kullanmak için yapmanız gerekir

  • notify() veya notifyAll() başka bir paylaşılan alana bir devlet değişikliğinden sonra.
  • Durum değişikliğini kontrol etmek için wait() için bir while döngüsü kullanmalısınız.

başka iş parçacığı bekleyen değilse

  • bildirmek bu kaybedilebilir yapmazsak.
  • Bekleme bildirilmediğinde bile, bekletmeden uyanabilirsiniz.
  • düzenleme kodunda sürülmektedir yukarıda ne gereği için

? Birden fazla iş parçacığı için aynı nesneyi nasıl paylaşırım? Bunun yerine Tamsayı sarıcı sınıfını kullanarak

public class PingPong implements Runnable {  
    static class Shared { int num; } 

    private final Shared var; 
    private final int bit; 

    public static void main(String[] args) { 
     Shared var = new Shared(); 
     new Thread(new PingPong(var, 0), "EvenThread").start(); 
     new Thread(new PingPong(var, 1), "OddThread").start(); 
    } 

    PingPong(Shared var, int bit) { 
     this.var = var; 
     this.bit = bit; 
    } 

    @Override 
    public void run() { 
     try { 
      String name = Thread.currentThread().getName(); 
      while (true) { 
       synchronized (var) { 
        while (var.num % 2 == bit) 
         var.wait(); 

        var.num++; 
        System.out.println(name + " " + var.num); 
        var.notify(); 
       } 
      } 
     } catch (InterruptedException e) { 
      System.out.println("Interrupted"); 
     } 
    } 
} 
+2

Bu yüzden her zaman 'final ''' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' 'kullanmak için mümkün değildir, serileştirme nesnelerini kullanarak' senkronize'', 'bekle'' veya' bildirim ' – ortis

+0

@ortis ile uğraşırken kullanmalısınız. etkin bir şekilde final. +1 –

+1

Bu yanıt atandı. Beklemenin nasıl kullanılacağını açıklar (bir süre (koşulNotMet) {waitOnTheLockObject;}). Bu cevap kabul edilmeli. @PeterLawrey, bununla birlikte, eğer ilkeller için tüm sarıcı sınıflarının değişmez olduğunu ve açıkça ifade ederseniz, güzel olacak. Tamsayıda var ++'nin neden yeni bir Tamsayı nesnesi oluşturacağını açıklayacaktır (açık olarak). – Amudhan

-1

, benim kendi sınıfını yarattı ve şimdi iyi çalışır. OP `notify` değil` wait` üzerinde istisna elde ettiğini

package mywaitnotifytest; 

public class App { 
    public static void main(String[] args) { 
     MyInt i = new MyInt(0); 
     Even even = new Even(i); 
     even.setName("EvenThread"); 
     Odd odd = new Odd(i); 
     odd.setName("OddThread"); 
     even.start(); 
     odd.start(); 
    } 
} 

class Even extends Thread { 

    MyInt var; 

    Even(MyInt var) { 
     this.var = var; 
    } 

    @Override 
    public void run() { 
     while (true) { 
      try { 
       Thread.sleep(200); 
      } catch (InterruptedException e1) { 
       // TODO Auto-generated catch block 
       e1.printStackTrace(); 
      } 
      synchronized (var) { 
       if (var.i % 2 == 0) { 
        try { 
         var.wait(); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
       var.i++; 
       System.out.println(Thread.currentThread().getName() + " " + var.i); 
       var.notify(); 
      } 
     } 

    } 

} 

class Odd extends Thread { 
    MyInt var; 

    Odd(MyInt var) { 
     this.var = var; 
    } 

    @Override 
    public void run() { 
     while (true) { 
      try { 
       Thread.sleep(2000); 
      } catch (InterruptedException e1) { 
       // TODO Auto-generated catch block 
       e1.printStackTrace(); 
      } 
      synchronized (var) { 
       if (var.i % 2 != 0) { 
        try { 
         var.wait(); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
       var.i++; 
       System.out.println(Thread.currentThread().getName() + " " + var.i); 
       var.notify(); 

      } 
     } 

    } 
} 

class MyInt { 
    int i = 0; 

    public MyInt(int i) { 
     super(); 
     this.i = i; 
    } 

    @Override 
    public String toString() { 
     // TODO Auto-generated method stub 
     return "" + i; 
    } 

} 

+0

Orijinal sorunun nedenini açıklamadan bir geçici çözüm okumak okuyuculara yararsızdır. Lütfen yukarıdaki cevabı kabul edin. –

+0

Sebebi @Peter Lawrey. –

İlgili konular