OO电梯作业总结
(一)第五次作業(yè)
一、設(shè)計思路
生產(chǎn)消費者模型,輸入接口是producer,調(diào)度器是tray,電梯是customer。由于只有一架電梯,所以生產(chǎn)消費模型滿足以下條件:
互斥:生產(chǎn)者——生產(chǎn)者,消費者——消費者。
同步:生產(chǎn)者至少生產(chǎn)一次,消費者才能消費。
互斥問題我給get和put函數(shù)加了方法鎖。
二、調(diào)度策略:FAFS傻瓜電梯
遵循先到先服務(wù),所以調(diào)度器作用很小,只是完成托盤的功能。調(diào)度器內(nèi)部有一個請求隊列,還有put和get方法。輸入接口和電梯是兩個線程。輸入接口每收到一個請求,即時加入到調(diào)度器隊列里。電梯每執(zhí)行完一個請求,向調(diào)度器索要下一個請求。
三、類圖
四、度量分析
?
?
五、Bug分析
如何結(jié)束電梯線程?
調(diào)度器里面有一個close變量標(biāo)志是否收輸入結(jié)束了。輸入接口(使用put函數(shù))傳入為null的請求時,調(diào)度器會將close變?yōu)橛行?。電梯?zhí)行完最后一個任務(wù),get下一個請求。如果此時請求隊列為空,且close有效,電梯也結(jié)束線程。
?
但最開始,我把結(jié)束電梯的條件寫錯了,只要close有效就會結(jié)束。但可能還有請求沒來得及讀進調(diào)度器隊列。正確的get函數(shù)寫法是,如果請求隊列為空且close無效,說明輸入沒有結(jié)束,還要等待后面的請求,就先wait。不再滿足wait條件的時候,如果隊列仍為空且close變?yōu)橛行Я?#xff0c;就結(jié)束電梯。
?
第二個問題是,輸入結(jié)束時,我沒有調(diào)用put方法,而是單獨調(diào)用一個end函數(shù)改變close狀態(tài)。這樣會有一種情況:最后一個請求還在put函數(shù)里沒有進入請求隊列,但后面被緊接著調(diào)用了end函數(shù)把close置位了,此時也是請求隊列為空,close有效,最后一個請求就沒有執(zhí)行。解決方法是,結(jié)束輸入時,依然調(diào)用put函數(shù),傳入一個為null的請求。Put函數(shù)有synchronized修飾,必須一次一次調(diào)用。
六、互測bug
此次作業(yè)比較簡單,沒有發(fā)現(xiàn)互測的bug。
?
(二)第六次作業(yè)
一、設(shè)計思路
仍然是生產(chǎn)消費者模型,與第一次作業(yè)類似。
二、調(diào)度策略:ALS可捎帶電梯
在調(diào)度器里增加了一個flush函數(shù)。電梯用get方法得到第一個請求,稱為主請求。在去主請求fromfloor的過程中不捎帶,從from到tofloor時,每到達一層,用flush函數(shù)向調(diào)度器索要可以捎帶上的請求。捎帶條件是,捎帶請求與主請求同方向,且捎帶請求的fromfloor在電梯當(dāng)前floor到destination之間。Destination的初值是主請求的tofloor,在電梯每次收到捎帶請求的時候更新為主請求和捎帶請求tofloor里面更遠的那個。
一開始我的電梯在到達主請求fromfloor的時候也可以捎帶,但是捎帶條件極其復(fù)雜,使用的不是destination,而是highestFromFloor,highestToFloor這些變量作為運動的終點。考慮到對第三次作業(yè)的可拓展性,我放棄了復(fù)雜的捎帶策略,但也因此沒有拿到性能分。
三、類圖
?
四、度量分析
?
五、bug分析
從第一次作業(yè)直接移植進出電梯的方法,出現(xiàn)了同一個人進兩次電梯的問題。所以我在電梯類里面設(shè)置了兩個請求隊列,一個是還沒進電梯的請求,一個是在電梯里面的請求,解決了這個問題。
如果在0秒出現(xiàn)兩個從1層進電梯的請求,我最初的寫法不能捎帶上第二個請求。在電梯剛到達一層,和開門之后都向調(diào)度器索要可以捎帶的請求,解決了這個問題。
六、互測bug
沒有發(fā)現(xiàn)同組的bug。調(diào)度策略越慢,越不容易出現(xiàn)bug,傳統(tǒng)的捎帶策略最保險。
?
(三)第七次作業(yè)
一、設(shè)計思路
在調(diào)度器里,給每個電梯設(shè)置一個隊列。輸入接口傳入一個請求的時候,調(diào)度器根據(jù)分配策略分配給一個電梯隊列。
二、調(diào)度策略
調(diào)度器分配請求的原則是,優(yōu)先分配給能直達的電梯,都能直達的時候優(yōu)先級A>B>C。否則調(diào)用transfer函數(shù),進行換乘分配。
電梯從調(diào)度器屬于自己的隊列里取請求,和查看捎帶請求。
?
關(guān)于換乘:
將換乘請求分成兩個,分配給兩部電梯。
其中一個難點是,確保完成換乘的第一站,再開始第二站。我新建了一個TransferRequest類保存換乘請求的id,負(fù)責(zé)第一站的電梯,第二站的電梯。將一個換乘請求分配好,就設(shè)置一個對應(yīng)的TransferRequest,存入換乘隊列。當(dāng)完成第一站請求(即人走出電梯)的時候,把它從換乘隊列刪除(transfered函數(shù)),執(zhí)行第二站的電梯檢測到隊列里沒有這個換乘請求了(檢測函數(shù)為transfering函數(shù)),才能執(zhí)行第二站。
三、類圖
?
四、度量分析
?
五、bug分析
我設(shè)計初期的bug圍繞著一個問題:電梯get第一個請求的時候,何時wait,何時結(jié)束運行?
Wait的時機是,電梯的請求隊列為空且輸入沒有結(jié)束,或者輸入結(jié)束電梯請求隊列不為空但所有都是沒完成第一站的換乘請求。相對的,每次輸入新請求和完成換乘第一站的時候,都要notify。
結(jié)束運行的時機還是,請求隊列為空,且輸入關(guān)閉。
六、互測bug
最常見的問題是多步電梯造成的線程沖突。有些同學(xué)讓三部電梯同時從一個請求隊列里搶請求,多個函數(shù)都會修改請求隊列,但沒有嚴(yán)格互斥。除了請求隊列,三部電梯還有其他共享數(shù)據(jù),對所有共享數(shù)據(jù)訪問的時候產(chǎn)生混亂。
?
(四)個人總結(jié)
我發(fā)現(xiàn)電梯的調(diào)度策略越簡單,可拓展性就越強,從第二次到第三次作業(yè),我寫的非???#xff0c;因為捎帶的調(diào)度策略完全不用修改,電梯類只增加了載客量,速度這兩個屬性。
但是如果想達到比較有效的優(yōu)化,就要從LOOK模式轉(zhuǎn)變成SCAN模式,工作量指數(shù)型增長。
?
SOLID原則:
轉(zhuǎn)載于:https://www.cnblogs.com/mollygarden/p/10745813.html
總結(jié)
- 上一篇: 助教小结4
- 下一篇: 3.4 实用的path变量