问题描述:父亲每次都会放一个水果在桌子上,女儿喜欢吃香蕉(只吃香蕉), 儿子喜欢吃苹果(只吃苹果)。父亲每次只会随机往桌子上放一个水果(苹果或香蕉),儿子,女儿会来取。使用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完成了一次取吃的操作
....