操作系统课设——吃水果问题
生活随笔
收集整理的這篇文章主要介紹了
操作系统课设——吃水果问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
問題描述:桌上有一盤子,桌上有一個空盤,允許存放一只水果,爸爸可向盤內放蘋果,媽媽可向盤內放桔子,兒子專等吃盤內的桔子,女兒專等吃盤中的蘋果。
package Fruit;import java.util.concurrent.locks.*;// java.util.concurrent 包含許多線程安全、測試良好、高性能的并發構建塊 /* 問題描述:桌上有一盤子,桌上有一個空盤,允許存放一只水果,爸爸可向盤內放蘋果,媽媽可向盤內放桔子,兒子專等吃盤內的桔子,女兒專等吃盤中的蘋果。 關鍵技術:鎖、Object類是Java中所有類的父類,是Java底層級別的,Condition是語言級別的,具有更高的可控制性和擴展性。 為什么要使用?Condition?利用Object的方式實際上是指在對象Object對象監視器上只能擁有一個同步隊列和一個等待隊列; 并發包中的Lock擁有一個同步隊列和多個等待隊列。 Condition能夠支持不響應中斷,而通過使用Object方式不支持 Condition能夠支持多個等待隊列(new 多個Condition對象),而Object方式只能支持一個 Condition能夠支持超時時間的設置,而Object不支持 Condition相比較而言,強大的地方在于它能夠精確的控制多線程的休眠與喚醒(注意是喚醒,喚醒并不表示該線程一定能夠得到資源鎖) Object的wait和notify,Condition使用await和signal 創建一個Condition對象是通過lock.newCondition() void await() throws InterruptedException//當前線程進入等待狀態,如果在等待狀態中被中斷會拋出被中斷異常 當前線程調用condition.await()方法后,會使得當前線程釋放lock然后加入到等待隊列中 直至被signal/signalAll后會使得當前線程從等待隊列中移至到同步隊列中去, 直到獲得了lock后才會從await方法返回,或者在等待時被中斷會做中斷處理。 void signal()//喚醒一個等待在condition上的線程,將該線程從等待隊列中轉移到同步隊列中,如果在同步隊列中能夠競爭到Lock則可以從等待方法中返回。如果不加上Thread.sleep()來讓線程睡眠,結果就像是單線程一樣,生產者填滿隊列,消費者清空隊列。 這個線程在釋放這個鎖之后會加入這個鎖的競爭中 修改sleep的睡眠時間,設置不同的休眠時間,可以觀察到生產者與消費者也不會出現交替進行,還是隨機的。 那么為什么要用Condition實現對確定線程的喚醒操作呢?喚醒了又不一定得到鎖,這個需要使用到await()來讓當前線程必須等到其他線程來喚醒才能控制生產者與消費者的交替執行。 Condition是個接口,基本的方法就是await()和signal()方法; Condition依賴于Lock接口,生成一個Condition的基本代碼是lock.newCondition() 調用Condition的await()和signal()方法,都必須在lock保護之內,就是說必須在lock.lock()和lock.unlock之間才可以使用 如果有多個消費者用Condition實現就非常簡單了,如果使用Object監視器類也可以實現但是相對復雜,編程過程中容易出現死鎖 */public class EatFruit {public static void main(String[] args) {Action r = new Action();Father father = new Father(r);Mother mother = new Mother(r);Son son = new Son(r);Daughter daughter = new Daughter(r);//thread每個線程都獨立,不共享資源 ,如果要共享需要加上同步條件synchronized //在程序開發中只要是多線程肯定永遠以實現Runnable接口為主。 //實現Runnable接口相比繼承Thread類有如下好處: //1、避免繼承的局限,一個類可以繼承多個接口。 //2、適合于資源的共享。Thread f = new Thread(father);Thread m = new Thread(mother);Thread s = new Thread(son);Thread d = new Thread(daughter);f.start();m.start();s.start();d.start();} }class Action //行為類,放水果和吃水果,完成初始化。 {//由于水果數量是在整個程序中貫穿的,應該使用全局變量static intprivate static int apple_number = 0,orange_number= 0,fruit_number = 0; // 蘋果數量,橘子數量,盤子中水果數量ReentrantLock lock = new ReentrantLock(); // 鎖對象 // 同一時刻只能有一個線程得到執行,另一個線程受阻塞,必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊 // synchronized和ReentrantLock作用類似,ReentrantLock是可以重入的鎖,當一個線程獲取鎖時,還可以接著重復獲取多次。 // synchronized只鎖定對象,每個對象只有一個鎖(lock)與之相關聯,多線程情況下會導致同時運行 // ReentrantLock操作較為復雜,但是因為可以手動控制加鎖和解鎖過程,在復雜的并發場景中能派上用場 // 創建一個Condition對象是通過lock.newCondition()Condition father_lock = lock.newCondition();Condition mother_lock = lock.newCondition();Condition parent_lock = lock.newCondition();Condition son_lock = lock.newCondition(); Condition daughter_lock = lock.newCondition(); private String name;// 放水果void put(String name) { // https://www.cnblogs.com/gemine/p/9039012.htmllock.lock();//調用Condition的await()和signal()方法,都必須在lock保護之內,就是說必須在lock.lock()和lock.unlock之間才可以使用try {Thread.sleep(1000);//如果不加上Thread.sleep()來讓線程睡眠,結果就像是單線程一樣,生產者填滿隊列,消費者清空隊列。} catch (Exception e) {e.printStackTrace();}try {while (fruit_number == 1) // 監測盤子是否有水果,如果已經有水果了,媽媽和媽媽都不能向里面放入水果,同構await實現當前線程進入等待狀態{try { // 測試多線程狀態下線程情況。 // System.out.print("盤中已有水果,禁止父母放入\n");parent_lock.await();//一開始分別設計了爸爸和媽媽的lock,但是發現沒有意義,必須掌握的是await和signal間的呼應關系 // System.out.print("父母線程進入等待狀態\n");} catch (Exception e) {e.printStackTrace();}}if (name == "爸爸") {apple_number = 1;fruit_number = 1;this.name = name; // 不加名字會變成nullSystem.out.println(this.name + "放蘋果");daughter_lock.signal();//已經驗證爸爸放入的水果,那么只有女兒能吃蘋果,喚醒女兒} else if (name == "媽媽") // 媽媽放了桔子{orange_number= 1;fruit_number = 1;this.name = name; System.out.println(this.name + "放桔子");son_lock.signal();//已經驗證媽媽放入的水果,那么只有兒子能吃桔子,喚醒兒子}} finally {lock.unlock();}}// 吃水果void eat(String name) {lock.lock();try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}try {if (name == "兒子") // 兒子{if (orange_number == 0) {try { // System.out.print("盤中沒有桔子,兒子線程進入等待狀態\n");son_lock.await();} catch (Exception e) {e.printStackTrace();}}orange_number = 0;fruit_number = 0;this.name = name; System.out.println(this.name + "吃桔子");parent_lock.signal();}else if (name == "女兒") // 女兒{while (apple_number== 0) {try { // System.out.print("盤中沒有蘋果,女兒線程進入等待狀態\n");daughter_lock.await();} catch (Exception e) {e.printStackTrace();}}apple_number= 0;fruit_number = 0;this.name = name;System.out.println(this.name + "吃蘋果");parent_lock.signal();}} finally {lock.unlock();}} }//線程的資源和 Thread 實例捆綁在一起,所以不同的線程的資源不會進行共享。 //線程資源與 Runable 實例捆綁在一起,Thread 只是作為一個代理類,所以資源可以進行共享。 class Father implements Runnable {private Action r;Father(Action r) {this.r = r;}public void run() {while (true) {//while語句可循環,if語句只會有一次操作 // 為什么要使用while而不是多次調用start // 線程的生命周期中,線程的狀態由NEW ----> RUNABLE只會發生一次, // 因此,一個線程只能調用start()方法一次,多次啟動一個線程是非法的。 // 特別是當線程已經結束執行后,不能再重新啟動。r.put("爸爸");}} // private void put(String string) { // // TODO Auto-generated method stub // // } }class Mother implements Runnable {private Action r;Mother(Action r) {this.r = r;}public void run() {while (true) {r.put("媽媽");}} }class Son implements Runnable {private Action r;Son(Action r) {this.r = r;}public void run() {while (true) {r.eat("兒子");}} }class Daughter implements Runnable {private Action r;Daughter(Action r) {this.r = r;}public void run() {while (true) {r.eat("女兒");}} }參考:https://blog.csdn.net/hkdg1651648029/article/details/76737959?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-3&spm=1001.2101.3001.4242
總結
以上是生活随笔為你收集整理的操作系统课设——吃水果问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 需求与业务的区别、需求设计与业务设计的区
- 下一篇: geth安装地址