现在的位置: 首页 > 综合 > 正文

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

2014年11月06日 ⁄ 综合 ⁄ 共 2897字 ⁄ 字号 评论关闭

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()方法唤醒线程是按照优先级的顺序呢? 还是其他?在网上搜的有两种说法,一种是按优先级,一种是说没有明确的顺序。 
当然,只要是人写的程序,总是会有一定规律的吧。

 

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

 

由于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!");
  }
 }

}

 

抱歉!评论已关闭.