关于生产者消费者在使用if条件时出错
今天学习了线程,写了个生产者消费者问题的代码如下
Test类
package com.xc.waitdemo3;
public class Test {
public static void main(String[] args) {
//创建公共区
Clerk clerk = new Clerk();
//创建线程
ProduceThread produceThread = new ProduceThread(clerk);
ConsumeThread consumeThread = new ConsumeThread(clerk);
//线程启动
produceThread.start();
consumeThread.start();
}
}
生产者
package com.xc.waitdemo3;
public class ProduceThread extends Thread {
Clerk clerk;
ProduceThread(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
while(true){
clerk.produce();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
消费者
package com.xc.waitdemo3;
public class ConsumeThread extends Thread {
Clerk clerk;
ConsumeThread(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
while(true){
clerk.consume();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
共享区
package com.xc.waitdemo3;
public class Clerk {
int product = 0;
/**
* 生产方法
*/
public synchronized void produce(){
if(product==20){
try {
//
System.out.println("等待消费。。。");
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("生产者生产了一个商品....."+product);
product++;
this.notify();
}
/**
* 消费方法
*/
public synchronized void consume(){
if(product<=0){
//
System.out.println("等待生产....");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" 消费者消费了一个产品:"+product);
product--;
notify();
}
}
此时我们消费者生产者调用的方法里面是使用if判断语句进行判断(分别在共享区的第12行和33行),此时我们运行代码,发现代码并没有问题,但是我们一旦多创建几个消费者问题就出现了
package com.xc.waitdemo3;
public class Test {
public static void main(String[] args) {
Clerk clerk = new Clerk();
//多创建几个生产者消费者
ProduceThread produceThread = new ProduceThread(clerk);
ConsumeThread consumeThread = new ConsumeThread(clerk);
ConsumeThread consumeThread2 = new ConsumeThread(clerk);
ConsumeThread consumeThread3 = new ConsumeThread(clerk);
produceThread.start();
consumeThread.start();
consumeThread2.start();
consumeThread3.start();
}
}
此时控制台出现了负数
很神奇,为什么一个消费者不会出现负数呢,于是我仔细研究了一下代码 发现问题就出现在if这里,下面来讲一下线程流程
如果库存已经没有产品了,此时消费者还想着来消费,就会被经过if条件判断,判断已经没有产品之后就会直接wait
假设来了四个消费者,经过判断全部被wait,此时生产者启动
当生产者生产好了一个产品,notify()一个消费者,这个被唤醒的消费者直接将产品消费掉,然后再notify其他被wait的线程,此时其他被wait的线程只剩下了三个之前被wait的消费者,但是此时被随机唤醒一个,唤醒之后直接进入下一步
已经为零的产品此时继续减减,然后就出现了负数,继续唤醒剩下两个消费者,于是继续减减,负的越来越多,而生产者根本忙不过来,此时就出现了负数。
而将if换成while时就会出现错误,是为什么呢?
是因为while()语句没有达成内部条件就不能出去,被唤醒的消费者再产品小于0时会被一直wait,知道有库存就可以出while循环此时就可以杜绝出现负数的情况。