简介:
今天看面试题时,看到wait的使用里面有一句话是wait,notify要用while,而不能用if。想了半天不知道为什么,看到大佬说在生产者消费者模式下会出错。于是我测试了如下
用if举例
写一个工厂类,有生产和消费方法,以及生产的产品数组
public class Factory {
//存放生产的数组
public char[] data = new char[5];
//data数组有效元素个数
public int count;
//生产的方法
public synchronized void push(char c){
if(count >= data.length){
try {
System.out.println(Thread.currentThread().getName() + "在等待");
this.wait();
System.out.println(Thread.currentThread().getName() + "等待结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
data[count++] = c;
System.out.println(Thread.currentThread().getName() + "生产了" + c);
//执行到此处说明生产完毕,所以唤醒等待该资源的消费者线程,this.notify();会在push方法执行完执行
this.notify();
}
//消费的方法,返回消费的值
public synchronized char pop(){
if(count <= 0){
try {
System.out.println(Thread.currentThread().getName() + "在等待");
this.wait();
System.out.println(Thread.currentThread().getName() + "等待结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "正在消费");
char res = data[--count];
System.out.println(Thread.currentThread().getName() + "消费了" + res);
//执行到此处说明正在消费,所以唤醒等待该资源的生产者线程,this.notify();会在pop方法执行完执行
this.notifyAll();
return res;
}
}
写一个生产类和消费者类,将工厂的对象传递进去,调用
//这是生产者线程
public class Producer implements Runnable{
public Factory factory;
public Producer(Factory factory) {
this.factory = factory;
}
@Override
public void run() {
for(int i=0; i < 8; i++){
factory.push((char)(65 + i));
try {
//间隔0.1秒生产一个
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//这是消费者线程
public class Customer implements Runnable{
public Factory factory;
public Customer(Factory factory) {
this.factory = factory;
}
@Override
public void run() {
for(int i=0; i < 8; i++){
factory.pop();//消费
}
}
}
//主函数
public static void main(String[] args) {
Factory factory = new Factory();
Producer producer = new Producer(factory);
Customer customer1 = new Customer(factory);
//Customer customer2 = new Customer(factory);
new Thread(producer,"producer").start();
new Thread(customer1,"customer1").start();
//new Thread(customer2,"customer2").start();
}
当一个生产者一个消费者是运行如下,没有错误
当两个生产者或两个以上,一个消费者是运行如下,出现错误
出错原因
如上图,当customer2消费了A后 没有产品可以消费了,此时customer1和customer2都进入了pop,并且在等待。当customer2消费结束后,此时产品数量为0(count=0),而customer1已经在消费了,所以data[--count]结果是data[-1],所以出错