2016-04-07 32 views
2

Ana yöntemde bir liste var ve bu listeyi kullanmak için iki iş parçacığı yazmak istiyorum. Bazen senkronize blokta IndexOutOfBoundsException'ı yakalarım (iş parçacığı çağrıları kaldırdığında).indexOutOfBoundsException list.remove aynı anda 2 iş parçacığıyla (aynı anda) çalıştır

Ana yöntemi:

public class PC { 
    public static void main(String[] args) { 
     List<String> strings = new ArrayList<>(); 
     new Costumer("c1", strings).start(); 
     new Costumer("c2", strings).start(); 
     new Producer("p1", strings).start(); 
     new Producer("p2", strings).start(); 
     new Producer("p3", strings).start(); 
     new Producer("p4", strings).start(); 
    } 
} 

Müşteri sınıfı:

class Costumer extends Thread { 

    List<String> strings; 
    public Costumer(String n, List<String> strings) { 
     super(n); 
     this.strings = strings; 
    } 
    @Override 
    public void run() { 
     while (true) { 
      synchronized (strings) { 
       try { 
        if (strings.isEmpty()) { 
         strings.wait(); 
        } 
        strings.remove(0); // <- where exception is thrown 
       } catch (InterruptedException ex) { 
       } 
      } 
     } 
    } 
} 

Üretici sınıfı:

class Producer extends Thread { 

    List<String> strings; 

    public Producer(String n, List<String> strings) { 
     super(n); 
     this.strings = strings; 
    } 

    @Override 
    public void run() { 
     while (true) { 
      synchronized (strings) { 
       strings.add(String.valueOf(Math.random() * 1000)); 
       if (strings.size() == 1) { 
        strings.notify(); 
       } 
      } 
      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException ex) { 
      } 
     } 
    } 
} 

Yığın iz:

Exception in thread "c2" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 
     at java.util.ArrayList.rangeCheck(Unknown Source) 
     at java.util.ArrayList.remove(Unknown Source) 
     at Costumer.run(PC.java:40) 
+1

Bu kodla aldığınız hata kesinlikle değil. Ne düşünüyorsunuz? Arrays.asList' geri döndü? Javadoc'unu okudun mu? – Savior

+0

Ayrıca string üretmek ve bunları listeye eklemek için başka bir iş parçacığım var. Bunu özetledim. ana kodda yeni Arraylist var. –

+0

Bu yüzden problemi gerçekten üretiyorsa kendi kodunuzu test etmeniz gerekiyor. Btw: Listenin başlatılmasını düzelttikten sonra bile bu kodun sorunu yeniden üretemeyeceğini sanmıyorum. Bu nedenle, işitme cihazınızı bildiren kodu da gönderin (bu, bu listeyi yeniden doldurabileceğinden). – Tom

cevap

3

Kodunuzdaki sorun, Costumer sınıfınızda test edildiyse, bir süre ile değiştirilmesi gerekir, aksi takdirde yarış durumuyla karşılaşabilirsiniz. Nitekim bir tüketicinin bilgilendirilmeyi beklediğini, tellerin kilitlenmesini bekleyen bir tüketicimiz olduğunu ve dizeleri kilitleyen üreticiye sahip olduğumuzu ve yeni bir dize eklediğini ve daha fazla dize sahip olmadığımızı bildirdiğimizi söyleyelim. Bu yüzden kilidi açtıktan sonra, kilidin beklediği tüketicinin önce aldığını söyleyelim (evet, hatırlatılan tüketicinin hala kilidi alması gerekmediğini ve ilk önce kilidin açılması gerekmediğini unutmayın) Daha sonra bir String'i kaldırır, ardından ikinci tüketici (tüketici tarafından bildirilen) strings.wait()'dan başlar ve boş olup olmadığını kontrol etmeden strings.remove(0)'u arayarak IndexOutOfBoundsException'u alırsınız.

Başka bir deyişle kod bu şekilde olmalıdır:

@Override 
public void run() { 
    while (true) { 
     synchronized (strings) { 
      try { 
       while (strings.isEmpty()) { 
        strings.wait(); 
       } 
       strings.remove(0); 
      } catch (InterruptedException ex) { 
      } 
     } 
    } 
} 

Neyse bunun gibi garip hata önlemek için bir süre döngüye durumunuzu kaydırmak için iyi bir uygulamadır. Örneğin, ArrayBlockingQueue gibi bir sınıfta nasıl yapıldığını kontrol edebilirsiniz, tüm koşullar bir süre döngüsünde kontrol edilir.

+0

* "ikisi de ilk dizeyi kaldıracaklar" * Ve neden böyle düşünüyorsunuz? Çünkü OP'nin birden fazla yapımcı kullandığını düşünüyor musunuz? – Tom

+0

neden? anlamıyorum Sadece bir iş parçacığı uyanmak uyandırma. Dokümanları bilgilendir: "Bu nesnenin ekranını bekleyen tek bir iş parçacığını uyandırır." –

+1

@ mohammad_1m2 Bu, birkaç durumun olabileceği bir yarış durumu sorunudur. İşte bir tane: Bir tüketicinin haberdar edilmesini bekliyoruz, bir tüketicinin telleri kilitlemek için beklemesini bekliyoruz ve dizeleri kilitleyen bir üreticiye sahibiz ve bu da yeni bir ip ekliyor ve daha fazla dize sahip olmadığımızı bildiriyor.Bu yüzden kilidi açtıktan sonra, kilidin beklediği tüketicinin önce aldığını, daha sonra bir String'i çıkardığını, daha sonra bildirilen ikinci tüketicinin de strings.wait(); ve strings.remove (0) çağırır; Boş olup olmadığını kontrol etmeden => .IOOBE –

İlgili konular