一、 前言
oo的複雜程度可能和寫完的時間成正比,多項式時週三電工實習不帶電腦,到了計程車已經發展成週三下午5點開始寫readme……不過相比前幾次為語法耗費時間,計程車更多的是為設計來投入精力。多執行緒debug也很有意思,在寫多部電梯時,自己猛然發現除錯時加入的一句system.out.println竟然會對結果產生影響(事後才發現原來是輸出除錯資訊到控制台耗費了時間,導致輸出結束時其他執行緒的狀態資訊更新完成了,若不加輸出,其他執行緒更新尚未完成,發生錯誤),真的迷……
二、 多執行緒電梯
由於三部電梯的出現,想要讓他們在三個執行緒中自己完成排程,就不得不在乙個大請求佇列的基礎上,增加三個小的請求佇列,分別儲存三部電梯的請求。
每當inputhandler有了新的合法請求,就拿到大佇列的鎖,將其加入到大佇列中,叫醒排程器。同樣的,每當電梯跑完當前主請求,也會叫醒排程器。排程器被叫醒後,要把當前大佇列中的指令分給空電梯或能捎帶的電梯,直至inputhandler執行緒結束且四個佇列都為空,程式結束。
這次雖然要求使用繼承,但由於有捎帶的但電梯寫的並不好,索性直接重寫scheduler類。值得一提的是時間的處理。但電梯由於使用假時間,導致時間的計算冗餘重複。本次是使用系統時間,相應的就帶來了誤差,如由於程式執行導致的每層樓實際並不是3000ms,實際上會多出幾十毫秒。誤差的累計就導致了輸入較多時,開始出現明顯的時間誤差。因此我使用了消除誤差的方法,即在wait(3000)前,先計算所產生的誤差時間,將睡眠時間改為wait(3000-誤差),就使得時間完全滿足要求。
與之前的問題大致相同,圈複雜度和巢狀深度過大。出現問題的carry方法是用來判斷是否可以捎帶,**如下。
1不好的一點是沒用列舉而是以變數來表示狀態,但由於捎帶判斷條件比較複雜,可能也很難優化了。另乙個圈複雜度高的方法是opendoor方法,用來輸出,同樣的,因為加入了時間的誤差消除,使得方法更加複雜,**就不放了。/**2
* 查詢是否可被捎帶3*
@param
request4*
@return
捎帶返回true,否則返回false5*/
6public
boolean
carry(request request)
15else
if (elelist[request.get_ele() - 1].get_dir() == eledir.down && request.get_dstfloor() < elelist[request.get_ele() - 1].get_curflo()) 19}
20return
false;21
}22else 34}
35else
if (elelist[j].get_dir() == eledir.down && request.get_dir() == 2 && request.get_dstfloor() < elelist[j].get_curflo() && request.get_dstfloor() >=elelist[j].get_dstflo()) 40}
41}42}
43if (whichtocarry != 3)
48return
false;49
}50 }
bug方面,自己沒有被報bug,但是測試的程式問題較多。如捎帶無法判斷、時間計算錯誤等問題,可能是他沒來得及除錯導致的。
三、 ifttt
本次由於要掃瞄檔案,而檔案的位置(路徑)實際上包含在了檔案的名字中,因此沒有用到樹來儲存,而是使用hashmap來儲存,以檔案的路徑作為key,以其大小和最後修改時間作為value,對目錄進行snopshot。以一定時間間隔更新snopshot,對監控檔案進行查詢和比對,如果觸發則進行任務,否則繼續掃瞄。
我採用的是每條指令乙個執行緒。在更新snopshot後,每條指令開始對其監控檔案進行查詢。因此就出現了乙個問題:多條指令監控乙個檔案,有recover、detail、summary操作時,若recover先完成,很可能導致後兩者沒有被觸發而未記錄;recover後完成,很可能導致檔案變化兩次都被detail和summary捕捉到,記錄了兩次。這個問題是由於多執行緒的不確定性導致的,因此不算做bug。但當互測時還是被申報了,而且申報者說他解決這這個問題,我猜應該是將recover先不執行,保證一定觸發兩次。
可以看到,monitor類很可能成為了乙個god類,其中的snopshot方法和comparefile方法完全可以拿出來作為新的類。度量分析也印證了這個猜想:
如果將這兩個方法拿出來,情況會好很多。這是在設計上沒有想好就直接寫**的結果。comparefile方法複雜的原因,很大程度上是由於其中分了四種觸發器,拆成四個函式會大大降低複雜度。
這次作業由於分類樹設定的不好,導致同源錯誤很可能被多次掛樹,如我的modified判斷條條件多此一舉的判斷了大小,導致樹上的detail、summary、監控檔案、監控目錄都掛了紅……最後通過申訴解決了。我測試的**同樣出現了這個問題。除此之外,我已經多次通過讀手中最核心的運算部分的**,找到了難以測試的bug,也反映出了讀**的好處。
四、 計程車
計程車即使給了寫好的ui和map,也沒有幫助測試……由於100輛車每200毫秒運動一次,非常難觀察其運動的正確與否,很多時候當看到gui能正常執行,就基本判斷沒什麼bug了,因此讀**的重要性更加明顯。
本次我才用了100個計程車1個執行緒的假多執行緒,inputhandler執行緒輸入後,將請求發給scheduler執行緒。snopshot則將每200ms的位置快照傳送給排程器。排程器根據位置搜尋派單車輛,更新該車輛狀態,而taxilist則每200毫秒sleep一次,再讓所有車移動,然後叫醒排程器進行排程。
可以看到,許多方法出現了複雜度高的情況。由於車輛狀態較多,到知道move等方法的複雜。
我測試的**,出現了乙個問題。通過讀他的**發現,他在判斷派單車輛時,將信用大於當前佇列最優的車加入佇列,此後從中選擇距離最小的乙個,而忘記把信用較小的刪除。同時,我的**中也有個問題。快照對於每個位置的車輛,要用arraylist來儲存,否則用int存其車輛編號,會導致同一位置有多輛車時,實際只存了1輛。
五、 心得體會
這三次多執行緒作業,讓我從完全不會多執行緒的使用,到對鎖有了一定的理解,收穫很大。但是熬夜更加嚴重了emmm……每週三還要趕一天工才能將將完成。活著真好……
OO第二次部落格總結
第五次作業 度量圖 類圖 分析 這次作業的主要問題是對電梯請求如何分配給三部電梯,讓他們能夠同時工作且不出現問題。這其中涉及到了關於執行緒安全,資料同步的問題。但由於這是多執行緒的第一次作業,自己以前對多執行緒沒有一點概念,做此次作業之前查閱了很多資料,但還是有很多地方並沒有真正弄明白。這在此次作業...
OO第二次部落格作業
從第4次作業開始,就進入了多執行緒程式設計的環節。我個人對於多執行緒的理解就是在乙個程式在執行時有多個執行流,能夠實現多個執行緒併發執行的技術。由於能在同一時間內執行多個執行緒,因而能夠提公升計算機的整體處理效能。第五次作業分析 由於第五次作業是我第一次接觸到多執行緒程式設計,因此這次作業對於我來說...
OO第二次部落格作業
第五次作業和第六次作業因為一些個人原因被判了無效所以這裡就不拿出來分析了 捂臉 第七次作業 設計乙個簡單的計程車排程系統 類圖 度量分析 其實在剛看到指導書的時候,覺得排程規則十分複雜。週日看了一下午指導書之後才大概想到一點思路,接著就開始了一步步嘗試。其實這次作業的目標十分明確,每個執行緒的任務很...