java 与操作系统同步问题(三)————父亲儿子女儿水果问题
问题描述:父亲每次都会放一个水果在桌子上,女儿喜欢吃香蕉(只吃香蕉), 儿子喜欢吃苹果(只吃苹果)。父亲每次只会随机往桌子上放一个水果(苹果或香蕉),儿子,女儿会来取。使用p、v操作来完成父亲、儿子、女儿的同步行为模拟。
问题分析:由上述描述我们可以知道,桌子就是一个缓冲区(单缓冲),同一时刻,只能有一个人对它进行放和取得操作。所以桌子就是一个互斥信号量。而桌子上有苹果,且父亲没有放,儿子才能取,女儿也是同理。所以应该还有两个资源信号量:1 苹果 2 香蕉
在由题意分析可知,三个信号量的初始值应该为 1 0 0 因为桌子只能放一个水果。而在开始的时候,桌子上是空的(所以可以进行放的操作),所以苹果、香蕉初始资源量都为空。
代码实现:
1.信号量设定如下:
/** * 缓冲区是否满信号量 */ Semaphore empty; /** * 苹果信号量 */ Semaphore apple; /** * 香蕉信号量 */ Semaphore banana; empty = new Semaphore(1); apple = new Semaphore(0); banana = new Semaphore(0);
2.父亲的放的线程,只有在桌子互斥资源量可以用的时候才能进行放的操作。所以要先p一下桌子信号量。
Thread fatherThread = new Thread(new Runnable() { String className = "father"; @Override public void run() { // TODO Auto-generated method stub while(true) { Semaphore.Wait(empty, className); if (randomAB()) { System.out.println(className + "往盘子里放了一个苹果"); Semaphore.Signal(apple, className); } else { System.out.println(className + "往盘子里放了一个香蕉"); Semaphore.Signal(banana, className); } System.out.println(className + "完成了一次放的操作"); //随机生成休眠时间,代表放入产品的操作时间 long millis = (long) (Math.random() * 1000); try { Thread.sleep(millis); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } });
3.儿子的实现,要判断是否有苹果,没有的话就等待
Thread sonThread = new Thread(new Runnable() { String className = "son"; @Override public void run() { // TODO Auto-generated method stub while(true) { Semaphore.Wait(apple, className); System.out.println(className + "从盘子里取了一个苹果"); //随机生成休眠时间,代表放入产品的操作时间 long millis = (long) (Math.random() * 1000); try { Thread.sleep(millis); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(className + "吃了一个苹果"); Semaphore.Signal(empty, className); System.out.println(className + "完成了一次取吃的操作"); } } });
4.女儿的代码实现:原理跟儿子的类似
Thread daughterThread = new Thread(new Runnable() { String className = "daughter"; @Override public void run() { // TODO Auto-generated method stub while(true) { Semaphore.Wait(banana, className); System.out.println(className + "从盘子里取了一个香蕉"); //随机生成休眠时间,代表放入产品的操作时间 long millis = (long) (Math.random() * 1000); try { Thread.sleep(millis); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(className + "吃了一个香蕉"); Semaphore.Signal(empty, className); System.out.println(className + "完成了一次取吃的操作"); } } });
运行结果如下:
daughter被阻塞
son被阻塞
father往盘子里放了一个香蕉
father资源量足够,唤醒一个
father完成了一次放的操作
daughter从盘子里取了一个香蕉
daughter吃了一个香蕉
daughter完成了一次取吃的操作
daughter被阻塞
father往盘子里放了一个香蕉
father资源量足够,唤醒一个
father完成了一次放的操作
daughter从盘子里取了一个香蕉
father被阻塞
daughter吃了一个香蕉
daughter资源量足够,唤醒一个
daughter完成了一次取吃的操作
....