2016-09-03 36 views
0

我想创建单个变量生产者消费者解决方案,但我在Producer的notifyAll()方法中获取IllegalMonitorStateException。 我正在获取同步块中的锁,可能出现了什么问题?IllegalMonitorStateException当共享对象

/** 
* Write a description of class SingleProducerConsumer here. 
* 
* @author (your name) 
* @version (a version number or a date) 
*/ 
public class SingleProdCons 
{ 

    public static void main(String args[]) 
    { 
     Integer x = 0; 
     Thread producer = new Thread(new Producer(x),"Producer"); 
     Thread consumer = new Thread(new Consumer(x),"Consumer"); 
     producer.start(); 
     consumer.start(); 
    }  
} 

    class Producer implements Runnable 
    { 
     private Integer x; 

     Producer(Integer x) 
     { 
      this.x = x; 
     } 

     @Override 
     public void run() 
     { 
      synchronized(x) 
      { 
      while(x.equals(0)==false){ 

       //The value of the variable has not been consumed yet , we should wait here till it gets consumed 
       try{ 
       x.wait(); 
       }catch(InterruptedException ie) 
       { 
        System.out.println("Caught Exception : "+ie.getMessage()); 
       } 

      } 

      //Else initialze the variable and let it get used by the Consumer then 
      synchronized(x) 
      { 
       x=10; 
       x.notifyAll(); 

      } 
     } 

     } 

    } 

    class Consumer implements Runnable 
    { 
     private Integer x; 

     Consumer(Integer x) 
     { 
      this.x = x; 
     } 

     @Override 
     public void run() 
     { 
      synchronized(x) 
      { 
      while(x.equals(0)==true) 
      { 
       //The value has not been put by the Producer thread yet hence we should wait here 
       System.out.println("We are before the method call of the wait on the x object"); 
       try{ 
       x.wait(); 
       }catch(InterruptedException ie) 
       { 
        System.out.println("Caught the exception : "+ie.getMessage()); 
       } 
      } 
      } 

      synchronized(x) 
      { 
       System.out.println("Consuming : "+x); 
       x.notifyAll(); 
      } 

     } 

    } 

Exception in thread "Producer" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notifyAll(Native Method) 
    at Producer.run(SingleProdCons.java:55) 
    at java.lang.Thread.run(Thread.java:745) 
Exception in thread "Producer" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notifyAll(Native Method) 
    at Producer.run(SingleProdCons.java:55) 
    at java.lang.Thread.run(Thread.java:745) 
Exception in thread "Producer" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notifyAll(Native Method) 
    at Producer.run(SingleProdCons.java:55) 
    at java.lang.Thread.run(Thread.java:745) 
Exception in thread "Producer" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notifyAll(Native Method) 
    at Producer.run(SingleProdCons.java:55) 
    at java.lang.Thread.run(Thread.java:745) 

回答

2

这就是问题所在:

synchronized(x) 
{ 
    x=10; 
    x.notifyAll(); 
} 

明白,你不上变量同步是很重要的 - 你的对象上同步。因此,您将x的值修改为指向一个不同的Integer对象,然后您将对该不同对象调用notifyAll ...来自不拥有该对象的显示器的线程。

我强烈建议您不要使用Integer对象进行同步。理想情况下,使用不用于其他目的的任何对象 - 这使得更易于推理。

你仍然可以拥有你的x变量,并且记录它不应该被修改,除非线程持有合适的锁 - 但是使它独立于锁本身。

+0

好吧,这听起来很酷,但你是什么意思,没有用于任何其他purpose.If我使用私人最终矢量sharedQueue它很好地工作。 :) – Chetan

+0

@Chetan:我的意思是说你只用它来实现同步/等待/通知目的......这意味着即使修改了“守护”值,也可以有单个对象。例如,我会强烈建议*反对*,因为'Vector'上的操作本身是同步的,与您正在做的任何事情相关。只要你不得不担心其他代码将要获取/释放(并可能通知/等待)显示器,就很难推断你的代码。 –

+0

你的意思是使用不同的变量进行修改和等待/通知目的会有不同的变化? – Chetan