一、設計策略 (1)單電梯: a、線程分工: elevator、request兩個線程。 elevator線程主要負責乘客的接送和進出。 request線程是接收乘客信息。 control是緩衝器,用來保存elevator和request兩個線程共用的乘客隊列。 b、調度策略: 以電梯當前樓層和運行 ...
一、設計策略
(1)單電梯:
a、線程分工:
elevator、request兩個線程。
elevator線程主要負責乘客的接送和進出。
request線程是接收乘客信息。
control是緩衝器,用來保存elevator和request兩個線程共用的乘客隊列。
b、調度策略:
以電梯當前樓層和運行狀態為基準,如果電梯是上行的,並且高於當前樓層還有乘客要進出就上行,否則判斷是否低於該樓層有需求,如果有就下行。反之亦然,若是沒有需求,則令電梯停止。對於乘客的調度則是到了規定樓層,能出則出,能進則進。
(2)多電梯1.0:
a、線程分工:
elevator類的五個電梯線程以及request線程。
elevator線程主要負責乘客的接送和進出。
request線程是接收乘客信息。
control是緩衝器,用來保存elevator和request兩個線程共用的乘客隊列。
b、調度策略:
基於第一次作業的單電梯,將request中獲得的乘客,平分到每個電梯中。
(3)多電梯2.0:
a、線程分工:
elevator類的若幹個線程以及request線程。
elevator線程主要負責乘客的接送和進出。
request線程是接收乘客信息。
control是緩衝器,用來保存elevator和request兩個線程共用的乘客隊列,以及保存電梯類的個數。
b、調度策略:
擴展PersonRequest類的功能,便於進行換乘操作。根據ABC不同的電梯停靠樓層對接收的乘客進行分類。能夠直達的儘量直達,若是出現都能直達的情況根據ABC的優先順序進行分類。若是不能直達的,則根據出發樓層ABC進行分類,換乘樓層集中在固定樓層1、5、15,便於進行操作,減少開關門的時間損失。對於同類別的不同電梯的乘客調度同第二次作業,對於電梯的運行同第一次作業。
二、第三次作業的可擴展性(SOLID原則)
(1)SRP(單一職責)原則
request類主要進行生產者線程,elevator進行電梯的主要功能,control進行乘客信息的調度以及保存。三類的功能都不相同,符合單一職責的原則。在control中雖然有很多的方法,但是執行的目的都是十分簡單,還是符合單一職責原則。
(2)OCP(開放封閉)原則
因為沒有在寫作業時,沒有考慮代碼的可擴展性,很多方法在第三次多電梯的實現中,進行了些許的調整,如果該電梯還要進行一些擴展操作,我想對於這些方法還是應該要進行調整。因此我覺得第三次作業的OCP原則還是不是很好。
(3)LSP(替換)原則
第三次作業中我單獨寫了三個電梯類,沒有歸類到一個父類裡面,因為在創建類,以及執行過程中都是用的電梯序號,所以沒有這方面的問題。
(4)ISP(介面隔離)原則
對於不同電梯,通過電梯索引來對電梯進行操作,在後續的幾次拓展都得到一個很好的實現,所以相對來說介面隔離實現得比較好。但是對於電梯沒有通過屬性規範,而是獨立的建立了三個電梯類,我覺得這一方面的介面原則就處理得不是很好。
(5)DIP(依賴倒置)原則
control緩衝區元素的建立依賴request的運行,elevator的執行和建立依賴control,沒有出現迴圈依賴的情況,還是很好的滿足了依賴倒置的情況。
三、度量分析
(1)第一次作業:
UML
複雜度分析
a、dependency
b、 complexity
總結
複雜度較好,但是對於control的setUpFloor方法的複雜度就比較高,這跟我的調度策略有著很大的關係,四次用到迴圈,結果作為條件的一種嵌套,都增加了複雜度,而這些在後續幾次作業都有體現。
(2)第二次作業:
UML
複雜度分析
a、dependency
b、 complexity
總結
這一次作業的的獨立性相對比較好,但是複雜度分析有很多的方法爆紅,特別是setUpFloor的方法,我想應該是在該方法有四個迴圈,導致該方法的複雜度很高,而且得出的結果又會用來下一次的判斷條件,所以有一個嵌套的複雜度,但是關於該方法的修正沒有比較好的想法。
(3)第三次作業:
UML
複雜度分析
a、dependency
b、 complexity
總結
這次作業的依賴性除了MainClass因為需要其他類來輔助執行,所以相對來說大一點其他還好。複雜度分析圖中,相比於第二次作業,爆紅的方法又加了一個addRequest方法,因為這次作業的調度設計涉及指定樓層,在沒有找到一個統一的方法的時候,只能通過打表的方式進行調度,我覺得或許可以通過將該函數進一步細化,得到一個複雜度較好的函數。
(4)plantMUL
四、bug分析
(1)自我bug分析
互測測到的bug主要是錯誤使用了notify,隨機的喚醒線程使得我一些線程長睡不醒,改成notifyAll後就不會出現這樣的隨機性了。
值得一提的是第三次作業的中測,由於對於notifyAll、wait的理解不夠深入,導致我在關於wait對象一判斷就喚醒,出現了一些線程wait條件判斷被阻塞,導致測試RE差點死於中測。但是經過這一次我好好學習了notifyAll的使用,發現只有在wait對象狀態發生改變的時候,即true變成false,才能夠notifyAll。
(2)hack的bug
第一次作業hack到的是暴力輪詢的bug;第二次作業沒有hack到;第三次作業hack到的是RE的bug,我覺得應該就是我中測碰到的那個類型的bug。
五、bug策略
這次hack構造,主要從很長時間再來一個人hack暴力輪詢,通過一次來很多人hack調度分配線程衝突。但是碰到一些評測到無法復現的bug還是感到多線程就是運氣的問題,但是如果一個安全的程式不應該依賴於運氣,應該要有一個充分的維護。與第一單元相比,這一次的作業在調試,bug復現的難度上大大的提高,而且有時候原理搞不明白,也很難找到bug。所以我認為還是應該要細細的分析程式,通過自動測試的方式只能是一種手段,還應該從從線程的程度上考慮,避免阻塞的情況發生。
六、心得體會
在這一次作業中,從線程安全上考慮應該要理清楚線程的執行順序,線程共用的對象。設計原則上應該儘可能的符合開閉原則,減少一些重覆操作和閉合操作,防止死鎖的產生。多線程的體驗中,我學習到了一些設計模式,雖然理解還不是很透,但是對於多線程的協作感到十分的神奇,而且感覺十分的接近現實生活。而且感覺學習寫程式,不應該依賴於專有的設計架構,應該多想想多嘗試一些原理。不然再後續調bug,可能自己就算是小黃鴨講解程式,也還是不會找到程式的bug。同時這種多線程的使用,在過程式代碼中是相當難實現得,又進一步瞭解了面向對象程式!