BUAA_OO_2020_UNIT2

BUAA_OO_2020_UNIT2

1、程序結構分析

  • 第五次做業java

    UML & Mertrics算法

    ​ 電梯的調度問題,實質上就是任務的請求與分配問題,筆者在第五次做業中採用簡單的「生產者-消費者」模型,創建了Din線程做爲生產者解析輸入並增長運載請求,創建Elev線程進行輸出,待處理數據由主控類Ctrl維護,並做爲電梯「調度器」,前二者的操做由線程安全的Ctrl負責,後兩次做業也延續這樣的架構,事實是無需重構也應付得了本次迭代。但筆者請求隊列與調度器一體化,且只有一級調度,致使主控類異常臃腫。安全

  • 第六次做業數據結構

    UML & Mertrics多線程

    ​ 還是老三樣,第六次做業中擴展功能比較容易實現,進行相關類的方法擴寫,主要是實現多電梯線程,筆者Ctrl類的處理不是很好,下一次重寫了Ctrl架構

  • 第七次做業測試

    UML & Mertrics線程

    ​ 架構上沒有大的改動,爲實現換乘功能,筆者創建了MyReq類存儲PersonRequst與乘客現處樓號,並面向過程根據換乘地圖爲各型電梯創建了樓層映射機制設計

2、Bug分析

  • 第五次做業中主要遇到的是多線程初見的線程調度bug,主要是筆者當時沒有找到精準的notify()條件,竟然喚起了RUNNALBE的線程,因爲Ctrl是共享的,致使輸入被電梯線程阻塞,好在最終肯定了進入wait()的條件。
  • 第六次做業筆者體會到了線程安全問題在本單元的重要性,在處理電梯數目輸入時,筆者居然沒用輸入文檔的ElevatorInput.getElevatorNum(),而是用(new Scanner(System.in)).nextInt(),System.in被輸入接口與Scanner共享,致使輸入緩衝區線程不安全,筆者此次屬實拉了胯了,直接白給愉悅送走
  • 第七次做業又出現了惡性bug,當C型電梯上的乘客想去樓4時,筆者直接給他送到樓3,但樓3只有C能去,B接不到,此次強測也是差點翻車了,不過三次做業筆者的總體結構仍是能夠的,經過嚴格控制synchronized語句塊的分佈與使用,三次做業除了這些bug也沒有出現過死鎖或是數據冒險啥的難以復現的bug

3、互測策略

  • 第五次做業功能比較簡單,只要保證簡單的線程調度就只用考慮單電梯調度問題,能夠輸入30條從底樓到頂樓的數據測試他人是否完成了捎帶
  • 第六次沒進互測,不過筆者認爲能夠從電梯超載與輸入指令數最大化這兩方面進行hack
  • 第七次重點在於線程安全與換乘,能夠輸入僅1條須要換乘的指令,測試他人是否在換乘完成前相關電梯線程已退出,更能夠圍繞換乘問題,觀察三類電梯樓號的定義域能夠發現1,3,15是最特殊的3個換乘點,也能夠枚舉全部請求後排除直達請求進行換乘的完備hack

4、對象建立模式

  • 第五次做業只創建了輸入線程Din,電梯線程Elev,看到一些朋友把調度器也整成線程我是沒想到的,Din負責向Ctrl輸入數據,並在輸入及結束後喚醒全部WAITINGElevElev的結束條件是沒有待調度請求而且Din在結束後設置了無輸入的全局變量。具體調度策略方面,選用LOOK算法,但不管SCAN仍是LOOK,都損失了一個方向上的請求信息,總感受不太好。因而以後筆者就真香GREEDY了,打造了純貪心的電梯調度與電梯間調度策略3d

  • 第六次做業改動很少,主要是改變了Ctrl中的數據結構適配多部電梯,另外的重頭戲就是電梯間調度,筆者在本次將單電梯改成貪心電梯,與同窗交流中有的是用平均分配、隨機分配來分派任務到各個電梯,但筆者仍是採用了電梯間自由地貪心競爭策略。緣由是,設想有兩架Elev,一臺空載,一臺載有乘客,從同一樓號出發,對於某一請求而言,載人Elev由於電梯內請求而停靠或轉向的平均機率更高,空載更有可能搶到請求。實際上載客越少越能直接相應電梯外請求,這有效減少某些電梯一直空轉的概率,從而自動實現了優先級任務分配,提升了Elev並行率,每次上一我的也能夠Thread.sleep(5)提升並行率。還有就是這樣不用寫二級調度了

  • 第七次做業,鑑於要實現換乘,有必要維護須要換乘乘客的當前樓號,因而筆者新建了MyReq類改進PersonRequst,對於上文2、notify了運行線程的bug,筆者也找到了安全方便的方案

    for (int i = 0; i < elevNum; i++) {
                if (elevs.get(i).getState().equals(Thread.State.valueOf("WAITING"))) {
                    synchronized (elevs.get(i)) {
                        elevs.get(i).notifyAll();
                    }
                }
            }//先判斷是在wait()再notifyAll();

    同時要注意線程安全的坑,筆者是保證全部Elev最後一塊兒DEAD的,防止要換乘的電梯早退

    解決線程設計後,煩人的換乘問題來了,各型電梯的樓號定義域A = [-3, 1] ∪ [15, 20],B = [-2, 15] - {3}C = [1, 8] * 2 - 1,找到換乘點(A ∩ B) ∪ (A ∩ C) ∪ (B ∩ C) = (C - {3}) ∪ {-1, -2},筆者並不想寫二級調度,就創建了地址轉換,考慮ElevMyReq的解析,咱們只要在電梯A-C下完成MyReq在電梯內和在電梯外的樓號轉換就行,實際上完成前者就行,若電梯內getToFloor()非法,就將目的地改成換乘路徑最短的換乘點。電梯外的話,先假設上電梯,轉換後若目標就是當前樓層,就保留本來目的地,不然直接上電梯。筆者真是懶死了,這類特定情境問題仍是最好畫圖分析或打表,別像筆者敗在細節。

5、心得體會

​ 筆者本單元的做業效果並不理想,仍是對於線程安全的理解不深,以及沒有注重多線程程序設計中的細節問題致使bug,筆者仍是對本身的調度器耿耿於懷,筆者理應實現隊列,調度分離的,這樣的調度器耦合度過高了。

本站公眾號
   歡迎關注本站公眾號,獲取更多信息