2016-09-03 25 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