生产者消费者问题
生产者与消费者问题是多线程同步问题的经典案例。也称有限缓冲问题。
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 {
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(); } }
|
