問題描述:父親每次都會放一個水果在桌子上,女兒喜歡吃香蕉(只吃香蕉), 兒子喜歡吃蘋果(只吃蘋果)。父親每次只會隨機往桌子上放一個水果(蘋果或香蕉),兒子,女兒會來取。使用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完成了一次取吃的操作
....