黑马程序员技术交流社区

标题: 多线程关于生产者和消费者 [打印本页]

作者: 黄昆    时间: 2012-7-15 01:58
标题: 多线程关于生产者和消费者
//帮我看看下面出错的原因
class Consumer extends Thread {
private Store store=null;
public void run() {
  store=Store.getStore();
  store.consumer();
}
}
class Producer extends Thread {
private Store store=null;
public void run() {
  store=Store.getStore();
  store.produce();
}
}
class Store {
private int length=0;
private int size=10;
private static  Store s=null;
public Store(){}
public Store(int len,int size){
  this.length=len;
  this.size=size;
}
static {
  s=new Store();
}
public static Store getStore(){
  if(s!=null){
    return s;
  }
  return new Store();
}
//生产者方法
public synchronized void produce(){
  while(length==size){
   try {
    Thread.currentThread().wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  //此处用Thread.currentThred.notifyAll()会报错
  this.notifyAll();
  System.out.println(Thread.currentThread().getName());
  length=length+1;
  System.out.println(Thread.currentThread().getName()+"生产一件产品,当前数量为:"+length);
}
//消费者方法
public synchronized void consumer(){
  while(length==0){
   try {
    this.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  //通知生产者线程
                  //此处用Thread.currentThread().notifyAll()会报错
  this.notifyAll();
  length=length-1;
  System.out.println(Thread.currentThread().getName()+"消费一件产品,剩余数量为:"+length);
}
}
public class MainClass {
static Consumer con=null;
static Producer pro=null;
public static void main(String[] args) {
  
   
  for(int i=0;i<10;i++){
    con=new Consumer();
   con.start();
  }
  for(int i=0;i<10;i++){
    pro=new Producer();
   pro.start();
  }
}
}

作者: 黑马振鹏    时间: 2012-7-15 09:46
函数需要被对象调用,那么函数都有一个所属对象引用,就是this.同步函数使用的锁就是produce()和consumer()都是同步函数,此处用到this.notifyAll()肯定是没问题。
Thread.currentThread()是当前正在运行的线程。他们并非是同一个。
public synchronized void produce(){
        while(length==size){
         try {
          Thread.currentThread().wait();
         } catch (InterruptedException e) {
          e.printStackTrace();
         }
        }
        System.out.println(Thread.currentThread().getClass()+"----------------");                 //此处用Thread.currentThred.notifyAll()会报错
        this.notifyAll();
        System.out.println(this.getClass());        System.out.println(Thread.currentThread().getName());
        length=length+1;
        System.out.println(Thread.currentThread().getName()+"生产一件产品,当前数量为:"+length);
}
加上两句代码观察运行结果:
class testing1.Producer----------------
class testing1.Store

一个是对应的Producer线程,一个是Store
作者: 刘煜    时间: 2012-7-15 11:38
如果把两个this.notifyAll()都改成Thread.currentThred().notifyAll()后编译是能通过的,运行的时候会抛出java.lang.IllegalMonitorStateException.抛出这个异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程,这个异常会在三种情况下抛出:
1>当前线程不含有当前对象的锁资源的时候,调用obj.wait()方法;
2>当前线程不含有当前对象的锁资源的时候,调用obj.notify()方法。
3>当前线程不含有当前对象的锁资源的时候,调用obj.notifyAll()方法。
出现异常的原因是Object的notifyAll()、wait方法、notify方法使用是有条件的,条件就是当前线程必须含有当前对象的锁资源。在你的代码中producer和consumer都是同步函数,它们的锁资源是它们的所属对象引用this,指的是Store类对象,而Thread.currentThred()获取的是当前线程对象引用,当前线程引用没有含有当前对象的锁资源Store类对象,而你又调用了notifyAll()方法,所以肯定运行失败,抛出异常。在你的代码中处理该异常的方法就是只能用this.notifyAll()。
备注:当前线程不含有当前对象的锁资源也可以理解为当前线程不是此对象监视器的所有者。






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2