2015-12-09 5 views
-1

Я обновляю свои знания на Java и пытаюсь написать многопоточную программу Wait and Notify (Producer, Consumer). Идея состоит в том, что у двух есть поток производителей, который добавляет данные в список массивов и уведомляет потребительский поток, который ожидает блокировки, достигнутой потоком производителя. Код дает вывод не ожидаемый результат.Java multi threading wait and notify

enter image description here

Но что я ожидал увидеть это

enter image description here

Если вы видите оба потребительские потоки ставятся на ожидание. Когда 1-й поток производителя добавляет данные в arraylist и отправляет сигнал notifyall всем ожидающим потокам. Я припарковал поток Producer на 10 секунд, так что ожидающий поток успеет выбрать список массивов и отобразить содержимое массива. На данный момент размер массива должен быть 1.

package Threads_New; 

import java.util.ArrayList; 
import java.util.List; 

public class Producer_Consumer2 { 

    List<String> sharedList = new ArrayList(); 
    int count = 0; 
    Object o = new Object(); 

    public void producer() 

    { 

     synchronized (o) { 
      try { 
       Thread.sleep(2000); 
      } catch (InterruptedException ex) { 
       ex.printStackTrace(); 
      } 
      System.out.println(Thread.currentThread().getName() 
        + "-Adding a value-" + count); 
      count++; 
      sharedList.add("Apple-" + count); 
      o.notifyAll(); 
      System.out.println("The Waiting thread is notified"); 
      try { 
       Thread.sleep(10000); 
      } catch (Exception ex) { 
       ex.printStackTrace(); 
      } 

     } 

    } 

    public void consumer() { 

     System.out.println(Thread.currentThread().getName() 
       + "- came inside consumer"); 
     synchronized (o) { 
      try { 
       o.wait(); 
       System.out.println(Thread.currentThread().getName() 
         + "- Notification recieved"); 
      } catch (InterruptedException ex) { 
       ex.printStackTrace(); 
      } 
      System.out.println("I was waiting and now got notified"); 
      for (String s : sharedList) { 
       System.out.println("Data from the sharedList is:" + s); 
      } 

     } 
    } 

    public void ThreadStarter() { 
     Thread[] T = new Thread[3]; 
     int run = 0; 
     while (run < 2) { 
      T[run] = new Thread(new Runnable() { 

       @Override 
       public void run() { 
        producer(); 
       } 
      }); 

      T[run + 1] = new Thread(new Runnable() { 

       @Override 
       public void run() { 
        consumer(); 
       } 
      }); 

      /* 
      * for(int i=0;i<10;i++) { t1.start(); t2.start(); } 
      */ 

      T[run].start(); 
      T[run + 1].start(); 
      run++; 
     } 

     /* 
     * for(int i=0;i<21;i++) { try{ T[i].join(); T[i+1].join(); 
     * }catch(InterruptedException ex) { ex.printStackTrace(); } } 
     */ 

    } 

    public static void main(String[] args) { 
     Producer_Consumer2 pc = new Producer_Consumer2(); 
     pc.ThreadStarter(); 
    } 

} 
+0

Если это на самом деле предполагается использовать рассмотреть возможность использования BlockingQueue вместо https://docs.oracle.com/javase/8/docs/api/java/ util/concurrent/BlockingQueue.html – kervin

+1

Попытка управлять многопоточным кодом с помощью спальных мест никогда не заканчивается. – sstan

+0

Почему существует ожидание у вашего потребителя? Вы уверены, что понимаете, как эти примитивы работают вместе с синхронизированными? Как правило, гораздо проще использовать утилит библиотеки более высокого уровня в параллельном пакете. – pvg

ответ

0

Я думаю, что по крайней мере часть проблемы вы сталкиваетесь в том, что производитель держит объект блокировки, даже когда он спит. Вы должны поставить синхронизированный блок (o) прямо там, где вы его уведомляете.

1

Предположительно, сон в вашем продюсере должен имитировать период времени, в котором он ничего не производит, и потребитель должен продвинуться вперед в течение этого времени. Но это невозможно, потому что код производителя все еще находится внутри блока synchronized. Вам необходимо переместить sleep за пределы блока synchronized.

Кроме того, ваш потребитель звонит wait, не убедившись, что его ждет, еще не произошло. Это очень серьезная ошибка, потому что, если вы ждете чего-то, что уже произошло, вы можете долго ждать.

0

Метод wait() должен быть вызван внутри цикла, чтобы проверить удовлетворительное условие, чтобы предикат, который вы ожидаете, был истинным, прежде чем продолжить, иначе это может привести к ложным пробуждениям. Java документ ссылку на метод Wait():

http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#wait%28%29