目录
最原始的生产者消费者模型
问题一 :产品product >= 1 时wait
问题二:增加一些消费者和生产者线程
package com.juc;
/*
* 生产者和消费者案例
*/
public class TestProductorAndConsumer1 {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Productor pro = new Productor(clerk);
Consumer cus = new Consumer(clerk);
new Thread(pro, "生产者 A").start();
new Thread(cus, "消费者 B").start();
/* new Thread(pro, "生产者 C").start();
new Thread(cus, "消费者 D").start();*/
}
}
//店员
class Clerk{
private int product = 0;
//进货
public synchronized void get(){
if(product >= 20){
System.out.println("产品已满!");
try {
this.wait();
} catch (InterruptedException e) {
}
}else {
System.out.println(Thread.currentThread().getName() + " : " + ++product);
this.notifyAll();
}
}
//卖货
public synchronized void sale() {
if (product <= 0) {
System.out.println("缺货!");
try {
this.wait();
} catch (InterruptedException e) {
}
} else {
System.out.println(Thread.currentThread().getName() + " : " + --product);
this.notifyAll();
}
}
}
//生产者
class Productor implements Runnable{
private Clerk clerk;
public Productor(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
clerk.get();
}
}
}
//消费者
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk.sale();
}
}
}
运算结果:
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
生产者 A : 1
生产者 A : 2
生产者 A : 3
生产者 A : 4
生产者 A : 5
生产者 A : 6
生产者 A : 7
生产者 A : 8
生产者 A : 9
生产者 A : 10
这个实例看着没有问题 如果把进货的 product >= 20 改为 product >= 1 运行程序会发现程序不会停止
修改后的运行结果:
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
生产者 A : 1
产品已满!
看最后三个结果:
消费者 B : 0
生产者 A : 1
产品已满!
原因在于 :当消费者循环都运行完之后,消费者 B : 0 然后唤醒了生产者线程,之后 生产者 A : 1 唤醒了生产者和消费者线程,但是消费者线程已经执行完毕,最后只能执行生产者线程,由于产品已经满了所以只能wait不能执行下去 ,一直在等待着其他线程唤醒生产者线程,就出现了程序一直在等待。
解决:去除else
package com.juc;
/*
* 生产者和消费者案例
*/
public class TestProductorAndConsumer1 {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Productor pro = new Productor(clerk);
Consumer cus = new Consumer(clerk);
new Thread(pro, "生产者 A").start();
new Thread(cus, "消费者 B").start();
/* new Thread(pro, "生产者 C").start();
new Thread(cus, "消费者 D").start();*/
}
}
//店员
class Clerk{
private int product = 0;
//进货
public synchronized void get(){//循环次数:0
if(product >= 1){//为了避免虚假唤醒问题,
System.out.println("产品已满!");
try {
this.wait();
} catch (InterruptedException e) {
}
}
System.out.println(Thread.currentThread().getName() + " : " + ++product);
this.notifyAll();
}
//卖货
public synchronized void sale() {//product = 0; 循环次数:0
if (product <= 0) {
System.out.println("缺货!");
try {
this.wait();
} catch (InterruptedException e) {
}
}
System.out.println(Thread.currentThread().getName() + " : " + --product);
this.notifyAll();
}
}
//生产者
class Productor implements Runnable{
private Clerk clerk;
public Productor(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
clerk.get();
}
}
}
//消费者
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk.sale();
}
}
}
结果:(一共出现20个缺货 以及20个消费者B)
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
缺货!
生产者 A : 1
消费者 B : 0
出现该结果的原因在于 去掉了else循环 所以每次循环都会打印缺货 然后线程wait 进而生产者生产产品 唤醒消费者线程 最后打印消费者
上面的情况适合一个消费者以及一个生产者情况 但是多几个生产者消费者会出现以下问题:
增加一个消费者和生产者:
public static void main(String[] args) {
Clerk clerk = new Clerk();
Productor pro = new Productor(clerk);
Consumer cus = new Consumer(clerk);
new Thread(pro, "生产者 A").start();
new Thread(cus, "消费者 B").start();
new Thread(pro, "生产者 C").start();
new Thread(cus, "消费者 D").start();
}
结果:
缺货!
缺货!
生产者 A : 1
消费者 D : 0
缺货!
消费者 B : -1
缺货!
生产者 C : 0
消费者 B : -1
缺货!
消费者 D : -2
缺货!
消费者 B : -3
缺货!
消费者 D : -4
缺货!
消费者 B : -5
缺货!
消费者 D : -6
缺货!
消费者 B : -7
缺货!
消费者 D : -8
缺货!
消费者 B : -9
缺货!
消费者 D : -10
缺货!
消费者 B : -11
缺货!
消费者 D : -12
缺货!
消费者 B : -13
缺货!
消费者 D : -14
缺货!
消费者 B : -15
缺货!
消费者 D : -16
缺货!
消费者 B : -17
缺货!
消费者 D : -18
缺货!
消费者 B : -19
缺货!
消费者 D : -20
缺货!
消费者 B : -21
缺货!
消费者 D : -22
缺货!
消费者 B : -23
缺货!
消费者 D : -24
缺货!
消费者 B : -25
缺货!
消费者 D : -26
缺货!
消费者 B : -27
缺货!
消费者 D : -28
缺货!
消费者 B : -29
缺货!
消费者 D : -30
缺货!
消费者 B : -31
缺货!
消费者 D : -32
缺货!
消费者 B : -33
缺货!
消费者 D : -34
缺货!
消费者 B : -35
缺货!
消费者 D : -36
缺货!
消费者 B : -37
消费者 D : -38
生产者 C : -37
生产者 A : -36
生产者 A : -35
生产者 C : -34
生产者 A : -33
生产者 C : -32
生产者 A : -31
生产者 C : -30
生产者 C : -29
生产者 A : -28
生产者 A : -27
生产者 C : -26
生产者 C : -25
生产者 A : -24
生产者 C : -23
生产者 A : -22
生产者 C : -21
生产者 A : -20
生产者 C : -19
生产者 A : -18
生产者 C : -17
生产者 A : -16
生产者 C : -15
生产者 A : -14
生产者 C : -13
生产者 A : -12
生产者 A : -11
生产者 C : -10
生产者 A : -9
生产者 C : -8
生产者 A : -7
生产者 C : -6
生产者 C : -5
生产者 A : -4
生产者 C : -3
生产者 A : -2
生产者 C : -1
生产者 A : 0
原因是因为:存在虚假唤醒
package com.juc;
/*
* 生产者和消费者案例
*/
public class TestProductorAndConsumer1 {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Productor pro = new Productor(clerk);
Consumer cus = new Consumer(clerk);
new Thread(pro, "生产者 A").start();
new Thread(cus, "消费者 B").start();
new Thread(pro, "生产者 C").start();
new Thread(cus, "消费者 D").start();
}
}
//店员
class Clerk{
private int product = 0;
//进货
public synchronized void get(){//循环次数:0
while(product >= 1){//为了避免虚假唤醒问题,
System.out.println("产品已满!");
try {
this.wait();
} catch (InterruptedException e) {
}
}
System.out.println(Thread.currentThread().getName() + " : " + ++product);
this.notifyAll();
}
//卖货
public synchronized void sale() {//product = 0; 循环次数:0
while (product <= 0) {
System.out.println("缺货!");
try {
this.wait();
} catch (InterruptedException e) {
}
}
System.out.println(Thread.currentThread().getName() + " : " + --product);
this.notifyAll();
}
}
//生产者
class Productor implements Runnable{
private Clerk clerk;
public Productor(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
clerk.get();
}
}
}
//消费者
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk.sale();
}
}
}
wait方法需要写在while循环中 不然存在虚假唤醒,当wait后被唤醒 还要去验证product是否大于1 然后再进行notifyAll。