生产者消费者问题
生产者与消费者问题是多线程同步问题的经典案例。也称有限缓冲问题。
| 12
 3
 4
 
 | # 什么是生产者消费者问题该问题描述了共享固定大小缓冲区的线程,生产者的主要作用是生成一定量的数据放到缓冲区,消费者也在缓冲区消耗这些数据。
 这类问题的关键在于保证生产者不会在缓冲区满时加入数据,消费者也不会下缓冲区空时消耗数据。
 
 
 | 
| 12
 3
 4
 5
 
 | # 如何解决这类问题生产者在缓冲区满时休眠,等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。
 同样,让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。
 
 通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己
 
 | 
问题
| 12
 
 | 桌上有一空盘,最多允许存放一个水果。爸爸可向盘中放一个水果或放一个橘子,儿子专等吃盘中的橘子。女儿专等吃苹果。试用P、V操作和Java程序实现爸爸,儿子,女儿三个并发进程的同步。
 
 | 
P、V操作
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | 根据题意,我们知道父亲是生产者,儿子、女儿是消费者。盘中的水果是共享资源。因为盘中最多允许存放一个水果,在生产前需要判断是否为满。
 
 利用互斥信号量mutex实现互斥,利用empty信号量来判断盘中是否为空。
 利用or信号量和ap信号量来判断盘中的橘子和苹果的数量。
 两个函数判断是否是橘子或者苹果。put(or) put(ap)
 
 设置初始值:
 mutex = 1  empty = 1  or = 0  ap = 0
 
 | 
| 12
 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程序
| 12
 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 {
 
 
 
 
 
 
 
 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();
 }
 }
 
 | 
