2014-10-27 52 views
0

如何在下面的程序中将一个线程从一个对象通知给另一个对象,而不使用以下生产者和消费者问题中的同步方法。通知另一个对象中的线程

我使用的是queue类的putget方法和Producer类和Consumer类的run()方法使用wait()notify()

我的目标是使用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。使用BlockingQueue时,不需要使用等待和通知。队列将等待并通知线程。消费者只需从队列中获取项目,然后队列将其阻塞,直到有可用项目。生产者只是将项目放入队列中,并且被队列阻塞,直到队列中剩余空间(如果有界限的话)。 – 2014-10-27 07:13:23

+0

线程之间共享的对象是队列,所以你必须在那里同步,而不是在生产者/消费者! – isnot2bad 2014-10-27 08:05:43

+0

将使用阻塞队列..感谢@ JB Nizer和isnot2bad。 – 2014-10-27 11:09:33

回答

3

方法waitnotify必须内​​块被调用。这就是为什么你会得到illegelMonitorStateException。

+0

oh..ok..thanks :)我可以同步运行方法..? – 2014-10-27 07:09:16

+0

我得到了异常删除。我可以明确地通知一个线程吗? – 2014-10-27 07:10:53

+0

要保持对象的监视器,你需要在这个对象上同步块。同步方法是错误的想法。 – 2014-10-27 07:12:41

2

线程之间共享的状态是您的Queue类,所以您必须通过使用适当的同步使其成为线程安全的。将同步代码放入您的ProducerConsumer不是一个好主意,因为这需要在它们之间进行额外的通信,并且不会扩展。

下面是一个简单的同步整数队列示例,它只能容纳一个单独的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(); 
} 
相关问题