OO5~7次作業總結
一、多線程電梯
1、類圖與流程圖
2、設計分析
此次作業中,出Main線程之外,我使用了一個調度器線程以及三個電梯線程。
調度器和電梯各自維護一個請求隊列,代表需要執行的請求。
Main線程負責從控制臺接收請求,進行輸入處理,並將合法的請求加入調度器線程中的請求隊列;
調度器線程從請求隊列中一條一條地取出指令,並根據電梯的狀態分配指令,即將指令加入到各個電梯的請求隊列中;
電梯線程從自己的請求隊列中取出指令,執行指令並輸出相關信息。
線程安全問題主要出現在對於各個線程的請求隊列的維護上。不同的線程對一個請求隊列進行添加,刪除操作,可能造成許多問題。應當使用線程安全的措施保障對請求隊列的各種操作。現在回想起來可以使用BlockingQueue簡化代碼。
3、Bug分析
此次作業公測部分沒有出現問題。但是在互測過程中出現了幾個BUG。
首先是readme的問題。同學認為對於一行多個請求結尾是一個分號的情況下應當進行空指令報錯。我認為分號後沒有指令並不應當進行空指令報錯,經過助教仲裁後決定這應當必須在readme中定義,故算作bug;
其次是電梯捎帶問題。對於同一時刻輸入的(FR,3,UP);(FR,2,UP);(FR,1,UP)這三條指令,我的程序中將其判斷為由一臺電梯捎帶,但是互測的同學認為這樣違背了電梯運動量均衡原則,所以應當由不同的電梯執行;
最後是輸出時間的問題。由於時間取自系統時間,所以時間間隔可能不是恰好的3s、6s。而且在程序運行過程中,隨著指令輸入的增多,時間誤差會越來越大,對於這個問題,我目前仍沒有想到一個萬無一失的方法能夠解決這個問題,還需要繼續學習探索。
二、IFTTT
1、類圖、度量分析與流程圖
2、設計分析
此次作業要求實現一個文件監視系統。我的核心思路就是對於每一個需要監控的對象,對於其每一種觸發器新建一個線程進行監視,如果滿足監視停止的條件那麽線程結束。
Main線程中主要負責輸入處理以及新建線程;
對於每個觸發器線程,在新建時進行初始信息的存儲,隨後以2s的周期掃描監視的文件目標,如果滿足觸發條件,執行相關動作;
測試線程用於對文件進行改動。
此次作業的線程安全問題主要出現在Detail和Summary向文件中寫入的時候。可能有多個觸發器線程同時需要向文件中輸出相關信息,所以應當將輸出文件的方法加鎖。
從度量分析中可以看出,此次作業的Main線程寫的比較倉促,將輸入處理以及各種初始化操作都直接寫在Main中,導致Main線程比較臃腫。同樣的問題還發生在四個觸發器線程中,在run方法中加入了過多的邏輯判斷,導致代碼可維護性差,需要在今後的作業中努力改善。
3、Bug分析
此次作業公測中,監控目錄並且掛載change-path觸發器時,要求輸出具體的文件路徑信息。我參考了issue中助教對於目錄detail的說法,即監控目錄時可以只輸出size信息,與公測要求相悖,錯了兩個點。不過並無大礙,僅僅是一句輸出語句的問題,程序的思路上沒有什麽大的問題。
三、模擬出租車調度
1、類圖、度量分析與流程圖
2、設計分析
此次作業要求實現一個模擬出租車調度系統。我的核心思路是首先啟動100個出租車線程,代表100輛出租車,隨後對於每一個輸入的有效指令,新建一個3s的調度線程,查找滿足要求的出租車,並分配指令。
Main線程從控制臺讀入叫車請求,建立調度器線程;
調度器線程讀取出租車狀態並且選擇最優的出租車分配請求,記錄信息並輸出到文件中;
出租車線程模擬出租車的運行,執行請求,記錄信息並輸出到文件中。
線程安全問題可能出現在兩個方面。首先,一輛出租車可以搶多個單,也就是說可能有多個請求的調度器要讀取甚至改變一輛出租車的狀態,那麽同一時刻只能允許一個調度器線程對出租車的狀態進行改變,對於出租車的指令分配需要加鎖。其次可能有多個線程同時向文件中輸出信息,也需要加鎖。
通過度量分析可以看出,此次作業在中調度器線程的run方法還是寫的有些臃腫,模塊化程度不高,還有提高的余地。
3、Bug分析
此次作業公測和互測均沒有發現Bug。互測過程中,同學的代碼完成度較差,問題較多,在這裏就不一一列舉了。
四、心得體會
通過5、6、7次作業,我對於多線程編程有了初步的了解,也學會了解決線程安全問題的一些方法。但是總的來說這些方法思路還是過於繁瑣,還有更多更加靈活,更加簡便的保障線程安全的方法,而且在開始編程之前一定要仔細思考各個對象,各個線程應當完成的工作是什麽,越詳細越明確越好,最好能從頭至尾遵循一個大的原則,這樣能避免編程過程中許許多多的問題,節省大量的時間,並且保證程序的可維護性。
互測過程中,發現Bug的首要方式應當是閱讀代碼。只有閱讀代碼才能發現對方程序中所有的問題。但是實際情況中,互測開始到結束的時間說短不短,說長也不長,在完成正常課程的同時閱讀源代碼,搞懂對方的思路實屬不易。特別是我們現階段沒有要求寫註釋,面對數百上千行的代碼,閱讀起來確實有些力不從心。不管怎麽說,原則上來說,閱讀代碼是必須要做的。除此之外,應當準備邊界數據,比如數字大小,規模邊界的測試樣例、還有特定時間的測試樣例、可能有線程安全問題的測試樣例,進行測試,也能夠發現一些問題。
對於線程安全問題,我的原則是首先完成基礎功能,再去思考多線程交互問題。也就是說,首先應當思考如何完成程序最基本的功能,將最基本功能實現之後,再去思考線程安全問題。判斷線程安全問題應當將每個線程需要讀、寫的屬性列出來,若Bernstein條件不滿足,那麽就存在線程安全問題。最通常的解決辦法就是加鎖,但是盲目加鎖會造成多線程的執行效率下降,甚至與單線程無異。所以加鎖的範圍要明確,要盡可能小。還要學會借助封裝好的工具來解決線程安全問題,如BlockingQueue等等。
我們之中有許多大牛,代碼美觀簡潔、功能完善,我的水平還差得很遠。但學習是個循序漸進的過程,如果每次作業都能有所收獲,大概也不虛此行吧。
OO5~7次作業總結