生产者消费者问题虚假唤醒
程序员文章站
2022-07-13 14:50:27
...
生产者消费者问题演示及解决
问题一:
package com.mock;
import org.junit.jupiter.api.Test;
public class TestProducerAndConsumer {
@Test
public void test() {
Product p = new Product();
new Thread(new Producer(p), "生产者1").start();
new Thread(new Consumer(p), "消费者1").start();
}
}
class Producer implements Runnable {
private Product product;
public Producer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
product.produce();
}
}
}
class Consumer implements Runnable {
private Product product;
public Consumer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
product.consume();
}
}
}
/**
* 货物
*/
class Product {
private int total = 0;
public synchronized void produce() {
if (total >= 6) {
System.out.println("货物已满");
} else {
System.out.println(Thread.currentThread().getName() + "---" + ++total);
}
}
public synchronized void consume() {
if (total <= 0) {
System.out.println("缺货中....");
} else {
System.out.println(Thread.currentThread().getName() + "---" + --total);
}
}
}
生产者1---1
生产者1---2
生产者1---3
生产者1---4
生产者1---5
生产者1---6
货物已满
货物已满
货物已满
货物已满
消费者1---5
消费者1---4
消费者1---3
消费者1---2
消费者1---1
消费者1---0
缺货中....
缺货中....
缺货中....
缺货中....
会出现数据丢失或者数据重复读的问题
解决方法,使用等待唤醒机制(wait() notifyAll())
package com.mock;
import org.junit.jupiter.api.Test;
public class TestProducerAndConsumer {
@Test
public void test() {
Product p = new Product();
new Thread(new Producer(p), "生产者1").start();
new Thread(new Consumer(p), "消费者1").start();
}
}
class Producer implements Runnable {
private Product product;
public Producer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
product.produce();
}
}
}
class Consumer implements Runnable {
private Product product;
public Consumer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
product.consume();
}
}
}
/**
* 货物
*/
class Product {
private int total = 0;
public synchronized void produce() {
if (total >= 6) {
System.out.println("货物已满");
try {
this.wait();
} catch (InterruptedException e) {
}
} else {
System.out.println(Thread.currentThread().getName() + "---" + ++total);
this.notifyAll();
}
}
public synchronized void consume() {
if (total <= 0) {
System.out.println("缺货中....");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println(Thread.currentThread().getName() + "---" + --total);
this.notifyAll();
}
}
}
生产者1---1
生产者1---2
生产者1---3
生产者1---4
生产者1---5
生产者1---6
货物已满
消费者1---5
消费者1---4
消费者1---3
消费者1---2
消费者1---1
消费者1---0
缺货中....
生产者1---1
生产者1---2
生产者1---3
消费者1---2
消费者1---1
消费者1---0
问题二
package com.mock;
public class TestProducerAndConsumer {
public static void main(String[] args) {
Product p = new Product();
new Thread(new Producer(p), "生产者1").start();
new Thread(new Consumer(p), "消费者1").start();
}
}
class Producer implements Runnable {
private Product product;
public Producer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
product.produce();
Thread.sleep(222);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
private Product product;
public Consumer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
product.consume();
}
}
}
/**
* 货物
*/
class Product {
private int total = 0;
public synchronized void produce() {
if (total >= 1) {
System.out.println("货物已满");
try {
this.wait();
} catch (InterruptedException e) {
}
} else {
System.out.println(Thread.currentThread().getName() + "---" + ++total);
this.notifyAll();
}
}
public synchronized void consume() {
if (total <= 0) {
System.out.println("缺货中....");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println(Thread.currentThread().getName() + "---" + --total);
this.notifyAll();
}
}
}
程序并没有停下来
问题分析:生产者生产有延迟,所以消费者循环的快,消费者先结束循环(有一次货物没有消费,没法唤醒等待着的生产者),生产者最后一次循环时进入货物已满逻辑进行等待,所以程序没有结束。
解决方法(去掉else)
package com.mock;
public class TestProducerAndConsumer {
public static void main(String[] args) {
Product p = new Product();
new Thread(new Producer(p), "生产者1").start();
new Thread(new Consumer(p), "消费者1").start();
}
}
class Producer implements Runnable {
private Product product;
public Producer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
product.produce();
Thread.sleep(222);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
private Product product;
public Consumer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
product.consume();
}
}
}
/**
* 货物
*/
class Product {
private int total = 0;
public synchronized void produce() {
if (total >= 1) {
System.out.println("货物已满");
try {
this.wait();
} catch (InterruptedException e) {
}
}
System.out.println(Thread.currentThread().getName() + "---" + ++total);
this.notifyAll();
}
public synchronized void consume() {
if (total <= 0) {
System.out.println("缺货中....");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "---" + --total);
this.notifyAll();
}
}
问题三(多个生产消费者)虚假唤醒
package com.mock;
public class TestProducerAndConsumer {
public static void main(String[] args) {
Product p = new Product();
new Thread(new Producer(p), "生产者1").start();
new Thread(new Consumer(p), "消费者1").start();
new Thread(new Producer(p), "生产者2").start();
new Thread(new Consumer(p), "消费者2").start();
}
}
class Producer implements Runnable {
private Product product;
public Producer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
product.produce();
Thread.sleep(222);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
private Product product;
public Consumer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
product.consume();
}
}
}
/**
* 货物
*/
class Product {
private int total = 0;
public synchronized void produce() {
if (total >= 1) {
System.out.println("货物已满");
try {
this.wait();
} catch (InterruptedException e) {
}
}
System.out.println(Thread.currentThread().getName() + "##" + ++total);
this.notifyAll();
}
public synchronized void consume() {
if (total <= 0) {
System.out.println("缺货中....");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "##" + --total);
this.notifyAll();
}
}
缺货中....
消费者1##-25
缺货中....
消费者2##-26
缺货中....
消费者1##-27
缺货中....
消费者2##-28
缺货中....
消费者1##-29
缺货中....
消费者2##-30
缺货中....
消费者1##-31
缺货中....
消费者2##-32
缺货中....
消费者1##-33
消费者2##-34
缺货中....
生产者1##-33
消费者2##-34
问题分析:两个消费者进入consume()方法消费,发现没有货物同时等待,生产者生产后唤醒消费者,两个消费者同时消费,会出现负数。
问题解决
需要循环判断,避免虚假唤醒
package com.mock;
public class TestProducerAndConsumer {
public static void main(String[] args) {
Product p = new Product();
new Thread(new Producer(p), "生产者1").start();
new Thread(new Consumer(p), "消费者1").start();
new Thread(new Producer(p), "生产者2").start();
new Thread(new Consumer(p), "消费者2").start();
}
}
class Producer implements Runnable {
private Product product;
public Producer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
product.produce();
Thread.sleep(222);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
private Product product;
public Consumer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
product.consume();
}
}
}
/**
* 货物
*/
class Product {
private int total = 0;
public synchronized void produce() {
while (total >= 1) {
System.out.println("货物已满");
try {
this.wait();
} catch (InterruptedException e) {
}
}
System.out.println(Thread.currentThread().getName() + "##" + ++total);
this.notifyAll();
}
public synchronized void consume() {
while (total <= 0) {
System.out.println("缺货中....");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "##" + --total);
this.notifyAll();
}
}
上一篇: 3.7 Java之打印流和数据流(附字符字节流练习)
下一篇: 原子性及CAS算法