生产者消费者问题

生产者消费者问题

生产者与消费者问题是多线程同步问题的经典案例。也称有限缓冲问题。

1
2
3
4
# 什么是生产者消费者问题
该问题描述了共享固定大小缓冲区的线程,生产者的主要作用是生成一定量的数据放到缓冲区,消费者也在缓冲区消耗这些数据。
这类问题的关键在于保证生产者不会在缓冲区满时加入数据,消费者也不会下缓冲区空时消耗数据。

1
2
3
4
5
# 如何解决这类问题
生产者在缓冲区满时休眠,等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。
同样,让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。

通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己

问题

1
2
桌上有一空盘,最多允许存放一个水果。爸爸可向盘中放一个水果或放一个橘子,儿子专等吃盘中的橘子。女儿专等吃苹果。
试用P、V操作和Java程序实现爸爸,儿子,女儿三个并发进程的同步。

P、V操作

1
2
3
4
5
6
7
8
9
根据题意,我们知道父亲是生产者,儿子、女儿是消费者。盘中的水果是共享资源。
因为盘中最多允许存放一个水果,在生产前需要判断是否为满。

利用互斥信号量mutex实现互斥,利用empty信号量来判断盘中是否为空。
利用or信号量和ap信号量来判断盘中的橘子和苹果的数量。
两个函数判断是否是橘子或者苹果。put(or) put(ap)

设置初始值:
mutex = 1 empty = 1 or = 0 ap = 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
三个进程
父亲:
P(empty)
if(put(or))
V(or)
else
V(ap)


儿子:
P(or)
V(empty)

女儿:
P(ap)
v(empty)

java程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import java.util.Random;

public class Fruit {

/**
* empty 的取值有不同的意义:
* 0 表示盘中无水果
* 1 表示盘中的水果是橘子
* 2 表示盘中的水果是苹果
*/
private int empty = 0;

//生产资源,,有生产者线程调用
public synchronized void put(){
while(empty != 0){
try{
System.out.println("盘中有水果,生产者正在等待");
wait();
}catch (Exception e){
}
}
//此时盘中无水果
Random random = new Random();
int randomInt = random.nextInt(2) + 1;
empty = randomInt;
if(empty == 1){
System.out.println("爸爸放入橘子");
}else{
System.out.println("爸爸放入苹果");
}
this.notifyAll();
}


//消耗资源,有消费者线程调用
public synchronized void get(){
while(empty == 0){
try{
System.out.println("盘中无水果,消费者等待");
wait();
}catch (Exception e){
e.printStackTrace();
}
}

//此时盘中有水果
empty = 0;
System.out.println("盘中无水果");
this.notifyAll();
}



public static void main(String[] args) {

Fruit fruit = new Fruit();

Thread father = new Thread(new Runnable() {
@Override
public void run() {
while(true)
fruit.put();
}
});

Thread daughter = new Thread(new Runnable() {
@Override
public void run() {
while(true){
while(fruit.empty == 2){
System.out.println("女儿拿到苹果");
fruit.get();
}
}
}
});

Thread son = new Thread(new Runnable() {
@Override
public void run() {
while (true){
while(fruit.empty == 1){
System.out.println("儿子拿到橘子");
fruit.get();
}
}
}
});
son.start();
daughter.start();
father.start();
}
}

image-20210415095401843


生产者消费者问题
https://johnjoyjzw.github.io/2020/12/05/生产者与消费者/
Author
John Joy
Posted on
December 5, 2020
Licensed under