日期:2014-05-20  浏览次数:20925 次

问一个多线程的问题?
我在做测试 生产者 消费者的时候 抛异常了
  0
存入货物:0
Exception in thread "producer" java.lang.IllegalMonitorStateException
取出货物:0
at java.lang.Object.notifyAll(Native Method)
at com.Thread.StoreHouse.put(StoreHouse.java:24)
at com.Thread.Producer.run(Producer.java:21)
Exception in thread "consumer" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at com.Thread.StoreHouse.get(StoreHouse.java:33)
at com.Thread.Consumer.run(Consumer.java:21)

下面是我调用 put get 的方法:
 

public class StoreHouse {

private static boolean available =false;//有货物

private static int number;//货物编号

public void put(int number) throws InterruptedException {
synchronized (StoreHouse.class) {
if(available)wait();//表示仓库有货 等待消费者取货
System.out.println("存入货物:"+number);
StoreHouse.number=number;
available=true;
notifyAll();
}
}

public void get() throws InterruptedException {
synchronized (StoreHouse.class) {
if(!available)wait();//表示仓库没货 等待生产者存货
System.out.println("取出货物:"+StoreHouse.number);
available=false;
notifyAll();
}
}

public static void main(String[] args) {
StoreHouse store=new StoreHouse();
Producer producer=new Producer(store,"producer");
Consumer consumer=new Consumer(store,"consumer");
producer.start();
consumer.start();
System.out.println(consumer.store.number);
}
}

大家帮忙看下为什么会抛这个异常啊.是什么原因.但是我把synchronized (StoreHouse.class) 换成synchronized (this)就不会. 请高手指教!!

------解决方案--------------------
按规范,你要wait就需要synchronized。

你的代码里面直接写 wait,其实就是 this.wait();所以必须在 synchronized(this) 块中。
------解决方案--------------------
请参考JDK的说明文档:

public final void wait() throws InterruptedException

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:

synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
 
This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.

------解决方案--------------------
首先明白什么情况下会出现这个异常:
wait(),notify(),和notifyAll()只能在同步方法里面调用(因为他们会操作锁)。
如果在非同步方法里面调用这些方法的话就会爆出IllegalMonitorStateException异常。其实异常提示的意思就是在调用wait()/notify()和notifyaLl()这些方法前必须拥有对象的锁。
你在put()方法里面调用了this.notifyall() 那么就要求你锁住当前这个对象 所以你写synchronized (this) 是没问题的。 但是如果你改成了 synchronized (StoreHouse.class) 那么你锁住的并不是当前的对象,而是StoreHouse的一个静态属性 XXX.class本身是XXX类的一个静态属性,也是一个对象。 所以你锁住的并不是当前你要操作的对象。
这样应该够明白了吧?