第二單元的做業是面向多線程的電梯編程,經過這一單元的做業,筆者基本掌握了多線程編程的方法。算法
task:單部先來先服務調度電梯,用戶請求能夠在任意時刻到達。編程
設計策略:安全
雖然第一次做業僅僅只有一部電梯,可是須要一個專門的線程用於處理輸入,與電梯線程併發執行。因爲須要準備向多電梯擴展,我在此次做業設計時並無直接將輸入給到電梯,而是通過了scheduler中轉後,再由電梯得到而後執行。多線程
此次做業我總共設計了兩個線程,InputHandler和Elevator,共享對象是Scheduler。InputHandler將處理好的請求放入Scheduler的隊列,ELevator將請求從Scheduler中取出而後執行。架構
所以爲了保證線程安全,須要對Scheduler的requests隊列的操做作同步控制,具體體如今InputHandler向requests隊列放入請求和Elevator從requests隊列取請求時都須要先得到requests隊列的鎖。併發
至於兩個線程之間的協同體如今1.requests隊列爲空時,電梯須要等待,我採用的是CPU輪詢的方法。2.InputHandler線程結束後,Elevator線程須要知曉,w爲此我在InputHandler中設置了一個hasInputFlag的變量,標誌是否還有輸出,電梯能夠經過查詢該標誌變量來檢查輸入線程是否結束,以便決定自身線程是否結束。框架
優勢:函數
缺點:單元測試
task:單部可捎帶電梯實現,用戶請求可隨時到達。測試
設計策略:
本次設計較第一次有了較大的改變。因爲調度器如今須要使用可捎帶算法來爲電梯分配請求,考慮到程序運行效率問題,調度器也能夠做爲一個單獨線程與InputHandler和Elevator線程併發執行。
此次做業筆者總共設計了三個線程:InputHandler、Elevator和Scheduler。InputHandler與Scheduler的共享區包括requests隊列和inputOver標誌;Scheduler與Elevator的共享區包括requests隊列和runOver標誌。
爲了保證線程安全,InputHandler對requests隊列的放入操做與Scheduler對requests隊列的取出操做都須要先申請鎖;Scheduler將請求放入電梯的requests隊列和電梯從本身的requests隊列中取請求都須要先申請鎖。
本次做業線程間的協做體如今:首先由InputHandler接收輸入進行處理後放入Scheduler請求隊列;而後Scheduler執行調度算法,將請求分配給電梯;最後電梯執行運行算法,完成請求。爲了實現三個線程間的同步控制,每得到一個輸入後,InputHandler對Scheduler進行notify;當requests隊列爲空時,Scheduler處於wait狀態;Scheduler每分配一個請求後,對Elevator進行notify;Elevator的requests隊列爲空時,Elevator處於wait狀態。這樣既能夠保證不浪費CPU時間,又可以保證各個線程及時被喚醒工做。
優勢:
缺點:
task:三部運行參數不一樣的電梯,使用可捎帶調度算法,用戶請求實時到達。
設計策略:
本次做爲是多部電梯的運行,並且每部電梯的屬性有所不一樣。三部電梯之間是併發執行的。
此次做業筆者總共設計了5個線程:InputHandler、Elevator和Scheduler。InputHandler與Scheduler的共享區包括requests隊列和inputOver標誌;Scheduler與Elevator的共享區包括每部電梯的requests隊列和runOver標誌。
爲了保證線程安全,InputHandler對requests隊列的放入操做與Scheduler對requests隊列的取出操做都須要先申請鎖;Scheduler將請求放入電梯的requests隊列和電梯從本身的requests隊列中取請求都須要先申請鎖。
本次做業線程間的協做體如今:首先由InputHandler接收輸入進行處理後放入Scheduler請求隊列;而後Scheduler執行調度算法,將請求分配給電梯;最後電梯執行運行算法,完成請求。爲了實現5個線程間的同步控制,每得到一個輸入後,InputHandler對Scheduler進行notify;當requests隊列爲空時,Scheduler處於wait狀態;Scheduler分配完當前隊列中全部請求後,對全部的Elevator進行notify;Elevator的requests隊列爲空時,Elevator處於wait狀態。
此次做業還新增了換乘的功能,爲了實現換乘,筆者的策略是在Scheduler中就首先拆分好,第一段交由電梯執行,第二段暫存在Scheduler的transfer隊列中,當第一段被電梯執行完畢後,電梯通知調度器對第二段進行分配,這樣就保證了第一段的永遠先於第二段執行,實現了同步控制。而且因爲transfer隊列的存在,Scheduler線程結束的條件不只是輸入結束和requests隊列爲空,還要算上transfer對列也爲空才能結束線程,當全部請求分配完畢後,若transfer隊列不空,Scheduler會進入wait狀態,等待電梯通知。
優勢:
缺點:
前三次做業在公測中都沒有出現bug,因爲未參加互測,所以沒有進一步發現bug。
多線程編程最重要的一點就在於線程安全的處理,凡是涉及到了線程共享的部分都須要進行加鎖操做。這裏就須要咱們找到到底哪些地方出現了共享,一般共享出如今參數傳遞、返回值、引用變量賦值這些地方,對於多線程編程中的這些場景咱們必定要格外注意,對於出現了共享對象,要追蹤其全部使用位置,檢查操做是否安全,不然一旦出現不可控的安全問題,靠debug來查找問題來源是極爲困難的。
除了多線程編程外,這一單元筆者同時還接觸到了設計原則。SOLID五大經典原則能夠說是在實際開發過程當中應該隨時恪守的,從需求分析到架構設計到代碼實現,每一步都要注意設計原則,並且在實現完成後還要進行設計原則的檢查,在不當的地方進行重構以符合設計原則。不少同窗可能很討厭這種工做,認爲又麻煩有沒有意義,可是筆者認爲在實際的軟件開發過程當中,遵照設計原則是極其重要的。如今因爲做業規模小,並且迭代開發次數少,不遵循設計原則看起來影響不大,一旦到了社會上,軟件的開發每每規模龐大並且要通過不少次的迭代開發。在這種狀況下,若是沒有一個統一的設計規範,一我的一套規則,那相互之間的合做就會變得無比困難,別人開發的軟件你可能徹底無法讀懂,更別談進行迭代開發;即便你可以讀懂,若是該產品通過屢次迭代後,有些類的安全性、獨立性等都已經發生了改變,那麼要想在已有基礎上進行修改,就可能須要向後追溯到好久之前實現的代碼上去進行閱讀,白白浪費大量時間。
總的來講,設計原則應該貫穿於整個軟件開發的過程,遵照設計原則,能夠幫助咱們更好的進行設計和開發。