2014-10-27 3 views
0

Как уведомлять поток из одного объекта в другой в нижеприведенной программе без использования синхронизированных методов в следующих проблемах производителя и потребителя.уведомлять потоки в другом объекте

Я использую queue класс для put и get методов и с использованием wait() и notify() в run() методе Producer класса и Consumer класса.

Моя цель состоит в том, чтобы использовать wait() и notify() методы в Producer класса и Consumer класса, а не использовать их в Queue классе.

Это дает IllegalMonitorStateException.

Программа:

package threads; 

class Queue{ 
    int num; 

    int get(int number) 
    { 

     System.out.println("The Consumer "+number+" got "+num); 
     return num; 
    } 

    void put(int n,int number) 
    { 

     this.num=n; 
     System.out.println("The producer "+number+" put "+this.num); 

    } 
} 

public class producerandconsumer{ 
    boolean flag=false; 
class Producer implements Runnable{ 
    Queue q; 
    int number; 
    Producer(Queue q,int number) 
    { 
     this.q=q; 
     this.number = number; 
     new Thread(this,"Producer").start(); 
    } 

    public void run() 
    { 
     for(int i=0;i<10;i++) 
     { 
      while(flag) 
       try{ 
        wait(); 
       } 
       catch(InterruptedException e){ 
        System.out.println("InterruptedException caught "); 
       } 
      q.put(i,number); 
      flag=true; 
      notify(); 
     } 
    } 

} 

class Consumer implements Runnable{ 
    Queue q; 
    int number; 
    Consumer(Queue q,int number) 
    { 
     this.q=q; 
     this.number=number; 
     new Thread(this,"Consumer").start(); 
    } 

    public void run() 
    { 
     for(int i=0;i<10;i++) 
     { 
      while(!flag) 
       try{ 
        wait(); 
        } 
        catch(InterruptedException e){ 
         System.out.println("InterruptedException caught "); 
        } 
       flag=false; 
       notify(); 
       q.get(number); 
     } 
    } 
} 



public static void main(String[] args) { 
    // TODO Auto-generated method stub 
    producerandconsumer pc= new producerandconsumer(); 
    Queue q=new Queue(); 
    pc.new Producer(q,1); 
    pc.new Consumer(q,1); 


} 

} 

Выход программы: Он дает IllegalMonitorStateException.

The producer 1 put 0 Exception in thread "Producer" 
java.lang.IllegalMonitorStateException 
at java.lang.Object.notifyAll(Native Method) 
at threads.producerandconsumer$Producer.run(producerandconsumer.java:48) 
at java.lang.Thread.run(Unknown Source) 

Exception in thread "Consumer" java.lang.IllegalMonitorStateException 
at java.lang.Object.notifyAll(Native Method) 
at threads.producerandconsumer$Consumer.run(producerandconsumer.java:76) 
at java.lang.Thread.run(Unknown Source) 
+2

Использовать BlockingQueue. Вам не нужно использовать wait и уведомлять при использовании BlockingQueue. Очередь будет ждать и уведомлять темы. Потребитель просто получает предметы из очереди, и очередь блокирует его, пока не появится доступный элемент. Продюсер просто помещает элементы в очередь и блокируется очередью, пока в очереди не осталось места (если оно ограничено). –

+0

Объект, разделяемый между потоками, это Queue, поэтому вам нужно синхронизировать его, а не в Producer/Consumer! – isnot2bad

+0

будет использовать Блокирующую очередь. Это @ JB Nizer и isnot2bad. –

ответ

3

Методы wait и notify должна быть вызвана внутри synchronized блока. Вот почему вы получаете исключение unlelMonitorStateException.

+0

oh..ok..thanks :) Могу ли я синхронизировать метод запуска ..? –

+0

У меня исключение исключение. могу я явным образом уведомлять поток? –

+0

Чтобы сохранить монитор объекта, вам понадобится синхронизированный блок на этом объекте. Синхронизированный метод - неправильная идея. –

2

Состояние, разделяемое между потоками, является вашим классом Queue, поэтому вам нужно сделать его потокобезопасным, используя правильную синхронизацию. Не стоит вводить код синхронизации в ваши Producer и Consumer, так как для этого требуется дополнительная связь между ними и не масштабируется.

Ниже приведен простой пример синхронизации целочисленной очереди, которая может содержать только один int (аналогично вашему Queue). Он блокируется, когда take вызывается в пустой очереди и когда put вызывается в заполненной очереди.

Обратите внимание, что вы должны использовать существующие синхронизированные структуры данных, такие как реализации BlockingQueue для приложений реального мира!

public class IntQueue { 
    int data; 
    boolean filled = false; 

    public synchronized int take() throws InterruptedException 
    { 
     while (!filled) { // wait for filled condition 
      wait(); 
     } 

     filled = false; // set not-filled condition 
     notifyAll(); // notify (other) waiting threads 

     return data; 
    } 

    public synchronized void put(int data) throws InterruptedException 
    { 
     while (filled) { // wait for not-filled condition 
      wait(); 
     } 

     filled = true; // set filled condition 
     notifyAll(); // notify (other) waiting threads 

     this.data = data; 
    } 
} 

Используя эту очередь вы можете иметь произвольное количество производителей и потребителей, которые не нуждаются в какой-либо дальнейшей синхронизации:

static final IntQueue queue = new IntQueue(); 
static final int POISON_PILL = -1; // stops Consumer 

class Producer implements Runnable { 
    public void run() { 
     try { 
      for(int i = 0; i < 100; i++) { 
       System.out.println("producing " + i); 
       queue.put(i); 
      } 
     } catch (InterruptedException ex) { /* done */ } 
    } 
} 

class Consumer implements Runnable { 
    public void run() { 
     try { 
      int n = queue.take(); 
      // poison pill causes Consumer to stop 
      while (n != POISON_PILL) { 
       System.out.println("consuming " + i); 
       n = queue.take(); 
      } 
     } catch (InterruptedException ex) { /* done */ } 
    } 
} 

public static void main() throws Exception { 
    // create threads 
    Thread p1 = new Thread(new Producer()); 
    Thread p2 = new Thread(new Producer()); 
    Thread c = new Thread(new Consumer()); 

    // start threads 
    p1.start(); 
    p2.start(); 
    c.start(); 

    // wait for producers to complete 
    p1.join(); 
    p2.join(); 

    // queue poison pill to stop consumer 
    queue.put(POISON_PILL); 

    // wait for consumer to complete 
    c.join(); 
} 
Смежные вопросы