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

关于多线程的notifyall()函数求教高手
本帖最后由 cloudeagle_bupt 于 2013-06-05 20:40:22 编辑
public class ThreadPriority {

public static void main(String[] args) {
Producer p = new Producer();
p.start();

for (int i = 1; i < 5; i++) {
Consumer cr = new Consumer();
cr.setPriority(i);
cr.start();
}

}

}

class Consumer extends Thread {
public Consumer()
{
setDaemon(true);
}
public void run() {
try {
synchronized (Producer.slotNum) {
if (Producer.slotNum == 0)
Producer.slotNum.wait();
Producer.slotNum--;
System.out.println(" Thread  " + this.getId() + " consumer 1!");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

class Producer extends Thread {

public static Integer slotNum = 10;

public Producer()
{
setDaemon(true);
}

public void run() {
synchronized (slotNum) {
slotNum++;
slotNum.notifyAll();
System.out.println(" Thread " + this.getId() + " producer 1!");
}
}

}

报错:Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
 Thread  10 consumer 1!
at java.lang.Object.notifyAll(Native Method)
at future.Producer.run(ThreadPriority.java:51)
 Thread  13 consumer 1!
 Thread  11 consumer 1!
 Thread  12 consumer 1!

ps:我一开始以为是slotNum++的问题,修改为slotNum=slotNum+1后还是报错,求指点啊
   搜了下,网上说: notifyAll()的描述,“解除那些在该对象上调用wait()方法的线程的阻塞状态。该方法只能在同步方法或同步块内部调用。如果当前线程不是对象所得持有者,该方法抛出一个java.lang.IllegalMonitorStateException 异常”
 
这里Producer 应该是slotNum 对象的持有者吧,而且notifyall和wait都是在同步块内调用的,为什么还会报出这样一个异常呢?

此外写这个代码的目的就是测试下,当一群线程在wait一个对象时, notifyAll()方法唤醒线程是按照优先级的顺序呢? 还是其他?在网上搜的有两种说法,一种是按优先级,一种是说没有明确的顺序。 
当然,只要是人写的程序,总是会有一定规律的吧。

------解决方案--------------------
问题不在Consumer 线程上面,而是在Producer线程上面
问题有2个
1 同步对象没有wait的前提情况下,已经notifyAll,这还不是错误的主要原因。
2 看一下如下代码

public void run() {
    synchronized (slotNum) {
        slotNum++;
        slotNum.notifyAll();
        System.out.println(" Thread " + this.getId() + " producer 1!");
    }
}


由于slotNum++;改变了监视的实例,所以导致当前线程不是此对象监视器的所有者。这才是真正的原因。
对象监视器不要是逻辑变量,你可以new一个object都是可以的。
------解决方案--------------------
你看一下你的main函数的线程的调用顺序

public static void main(String[] args) throws InterruptedException {