文章目錄
[OO] Unit2 Summary 電梯系列
架構相關
UML類圖
- 採用架構爲三類線程、分配器與控制器分離
請求處理流程
多線程協同與同步控制
時間線流程圖
- 我在這上次作業的多線程控制中,採用了由父線程創建子線程的方式
- 考慮到整個程序的結束是由InputThread發出的,所以將InputThread作爲Main創建的唯一線程,並且由InputThread再創建子線程
- 具體的線程管理方式可由流程圖看出
同步控制
- 大多數採用synchronized關鍵字進行同步與保護
- 少數使用現成的線程安全容器如ConcurrentHashMap與BlockingQueue等
- 關於線程終止的問題,我採用了父線程判斷什麼時候應當結束子線程,並通過interrupt嘗試停止子線程,最終使用join函數等待子線程都結束後再終止
第三次作業架構設計
可擴展性分析
- 經過第一單元的磨練,我在第二單元中儘可能地考慮了優化時的可擴展性,架構與性能的平衡
- 一個好的設計,一定是優化能夠方便地建立在架構上,並且這樣地優化策略能夠很好地擴展
- 具體的優化策略可以由我之前在研討課上地分享看到
- [OO] 第二單元 電梯優化策略
- 可以看到,對於可擴展性,只需要改變估價函數即可,估價函數的定義見上述博文
設計原則分析
原則 | 分析 |
---|---|
單一責任原則 | 經過多次小範圍重構,個人認爲我在分類與分包的顆粒度上做得很好 |
開放封閉原則 | 這一點做得較好,但在更改估價函數時,需要對原有代碼進行更改與封裝性破壞,似乎這不可避免 |
里氏替換原則 | 此次作業不適用,未使用繼承語法 |
依賴倒置原則 | 總體來講,這一點還好 |
接口分離原則 | 本次作業未使用接口,並且不同類之間差異較大,不需要使用接口進行抽象 |
基於度量分析
- 由於更新IDEA後MetricsReloaded插件無法使用,故使用DesignitiveJava進行一些簡要分析
- 由上圖LCOM(內聚缺乏度)可以看出,我的設計整體來說比較符合高內聚低耦合的特點,唯一需要增加內聚的是參數控制Config類,它既包含了全局的參數信息,又包含了每個電梯的特異性參數信息,應當將這兩種參數分開作爲兩個類
- 由FANIN(越大越好)與FANOUT(越小越好)指標可以看出,設計控制的部分類FANOUT較高,如Controller與DistributorThread
- 可能的原因是這兩個類承擔了較多的分配與控制任務,需要掌握的信息也比較多,因此引用其他類的次數也就較多
- 架構與流程圖和協作圖見上
BUG分析
自己的bug分析
- 電梯系列作業中,一共出現了2個BUG,都屬於線程安全的問題
- 兩個BUG具有相似之處,即某線程還未進入可相應Interrupt的狀態,卻受到了Interrupt,導致下一次到達某個該Sleep的地方提前中斷Sleep,最終導致相鄰兩個時間太短而WA
- 但神奇之處在於本地測試時很多次纔會爆出一個Bug,我在本地復現這個bug的時候遇到了極其難以復現的問題
- 即使最終能夠復現,同一個測試樣例也會在不同的時候WA,不可預估
- 最開始以爲是課程組評測機有問題,最終發現還是自己太年輕
- 所以如果這篇博客有幸能被學弟學妹們看到,請一定記住如果本地無法復現BUG,一定是有線程安全的問題,且需要關注極小的運行速度差別導致的問題
Hack策略
- 使用自動評測機,見[OO] 電梯系列 多進程強力自動評測機
心得體會
線程安全方面
- 在這一單元中,最難過的坎就是線程安全的問題,並且其難以復現性將debug的難度大大提升
- 遇到這樣的線程安全問題,不能盲目地急躁地debug,而是仔細地從代碼邏輯上形式化找線程安全的問題,需要充分考慮各種代碼執行情況
設計原則方面
- 關於設計原則,我最大的感受就是應當盡力遵從,如果某個地方不符合某個設計原則,不一定會出錯,但是這裏應當極大地仔細謹慎
- 總的來說,設計原則在這一單元地作業中主要體現在代碼質量上以及可維護性和可擴展性上,絕大部分遵從設計原則寫出來地代碼對作者和閱讀者都十分友好,這無疑是極具幸福感的事情
碎碎念
- 總體來說,第二單元相對於第一單元來說,更有趣和面向對象,電梯作爲OO課程的王牌果然名不虛傳…
- 相比於計算機組成課設、OS課設、編譯原理課設等我個人認爲較
死板機械的課程,OO課程在一定代碼量的基礎上,更多的是設計與創新這個靈魂,考驗的是玩家怎麼玩的嗨,而不是CO、OS、編譯等經常需要在一個毫無意義的bug上吊死一天,雖然OO有的bug也能吊死一天,但這樣的bug往往是設計上的缺陷,個人認爲這種纔是高級Bug,debug的時候可以很興奮