您的位置:首页 > 编程语言 > Java开发

Java的多线程NotiFyAll()唤醒线程时的顺序问题

2013-06-04 22:13 218 查看
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!

  搜了下,网上说: notifyAll()的描述,“解除那些在该对象上调用wait()方法的线程的阻塞状态。该方法只能在同步方法或同步块内部调用。如果当前线程不是对象所得持有者,该方法抛出一个java.lang.IllegalMonitorStateException 异常”
 
这里Producer 应该是slotNum 对象的持有者吧, 必然是先通过synchronized关键字获取slotNum的锁,在通知其他等待线程吧 ,而且notifyall和wait都是在同步块内调用的,为什么还会报出这样一个异常呢?

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

 

 

由于slotNum++;改变了监视的实例,所以导致当前线程不是此对象监视器的所有者。这才是真正的原因。
 由于做了自加操作,Integer 作了自动拆箱,自减完成后又自动装箱了,因此在 slotNum++之后的 slotNum 与之前的 slotNum 不是同一个对象了,所以在 notifyAll 时会抛出无效的监视器状态异常。

参考这个

http://stackoverflow.com/questions/260337/why-does-synchronized-notifyall-result-in-a-illegalmonitorstateexception

 

修改后的代码如下:

package future;

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadPriority {

 public static void main(String[] args) {

  

  for (int i = 1; i < 5; i++) {

   Consumer cr = new Consumer();

   cr.setPriority(i);

   cr.start();

  }

  

  Producer p = new Producer();

  p.start();

 }

}

class Consumer extends Thread {

 public Consumer()

 {

  setDaemon(true);

 }

 public void run() {

  try {

   synchronized (Producer.slotNum) {

    if (Producer.slotNum.get()== 0)

     Producer.slotNum.wait();

    Producer.slotNum.decrementAndGet();

    System.out.println(" Thread  " + this.getId() + " consumer 1!");

   }

  } catch (InterruptedException e) {

   // TODO Auto-generated catch block

   e.printStackTrace();

  }

 }

}

class Producer extends Thread {

 

 public static AtomicInteger  slotNum = new AtomicInteger(10);

 

 public Producer()

 {

  setDaemon(true);

 }

 

// public void addSlot()

// {

//  slotNum ++;

// }

 

 public void run() {

  synchronized (slotNum) {

//   slotNum++;

//   slotNum = slotNum +1 ;

//   addSlot();

   slotNum.incrementAndGet();

   slotNum.notifyAll();

   System.out.println(" Thread " + this.getId() + " producer 1!");

  }

 }

}

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: