OO課程已通過半,過去的第二單元主要是訓練了咱們的多線程設計,以電梯爲載體,步步深刻,層層遞進。本單元我學到了:java
下面我將以三次做業爲例,具體談一下個人收穫。python
此次做業的要求是寫一個傻瓜式調度的電梯,筆者也是按指導書去寫的,總體寫起來很輕鬆,也算入門了Java多線程的寫法、共享對象的使用以及鎖的使用。算法
第一次的業務邏輯很清晰,就是簡單的生產者-消費者模型,輸入類爲生產者,電梯類爲消費者,共享對象是調度器裏的請求隊列。能夠很簡單地實現傻瓜電梯的功能,也不容易出bug。安全
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
elevator.Elevator.Elevator(Scheduler) | 1 | 1 | 1 |
elevator.Elevator.moveToFloor(int) | 1 | 2 | 2 |
elevator.Elevator.personIn(int) | 1 | 2 | 2 |
elevator.Elevator.personOut(int) | 1 | 2 | 2 |
elevator.Elevator.run() | 3 | 3 | 3 |
elevator.Main.main(String[]) | 1 | 1 | 1 |
elevator.RequestIn.RequestIn(Scheduler) | 1 | 1 | 1 |
elevator.RequestIn.run() | 3 | 4 | 4 |
elevator.Scheduler.Scheduler() | 1 | 1 | 1 |
elevator.Scheduler.addRequest(PersonRequest) | 1 | 1 | 1 |
elevator.Scheduler.getQueue() | 1 | 1 | 3 |
elevator.Scheduler.getRequest() | 1 | 3 | 3 |
Class | OCavg | WMC | |
elevator.Elevator | 1.4 | 7 | |
elevator.Main | 1 | 1 | |
elevator.RequestIn | 2 | 4 | |
elevator.Scheduler | 1.75 | 7 |
能夠看到第一次業務邏輯簡單,代碼的複雜度也相對小一點,只有電梯的運行方法稍顯複雜,這也是情理之中的。多線程
本單元做業筆者未使用繼承和接口,因此如下只分析SRP和OCP。架構
筆者的設計符合SRP原則,輸入類只負責輸入,電梯只負責運行,調度器只負責存儲請求隊列。工具
筆者在第一次做業中暫未考慮擴展性問題。性能
筆者的程序在公測中未被發現bug。學習
筆者的程序在互測中未被發現bug。測試
隨機生成測試數據,用java程序按時間點向電梯輸入請求,獲得輸出後用python程序檢查最終的電梯狀態和人員狀態,看一下調度是否正確。
本次做業的要求是寫一個ALS調度算法的電梯,因爲此次做業加入了性能分評測,故筆者寫的電梯是Look調度算法。此次做業的邏輯稍顯複雜,怎麼去避免死鎖發生,怎麼去寫一個線程安全的架構是咱們考慮的重點。
第二次做業相比第一次做業,只增長了捎帶需求,而爲了適應多電梯的擴展,我對電梯系統作了重構,首先,增長Elevatorbuild類,負責生成多部電梯,而後Elevator按Look調度算法運行,每到一層樓都和Scheduler調度器進行一次交互,進行接送乘客。由於是單電梯,因此本次的調度器職責就是把收到的指令分配給電梯。
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
Main.main(String[]) | 1 | 1 | 1 |
elevatorsystem.RequestInput.RequestInput(Scheduler) | 1 | 1 | 1 |
elevatorsystem.RequestInput.run() | 3 | 4 | 4 |
elevatorsystem.Scheduler.addRequest(PersonRequest) | 1 | 1 | 1 |
elevatorsystem.Scheduler.getScheduler() | 1 | 1 | 3 |
elevatorsystem.Scheduler.setRunning(Boolean) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.Elevator() | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.check() | 1 | 6 | 8 |
elevatorsystem.elevator.Elevator.close() | 1 | 2 | 2 |
elevatorsystem.elevator.Elevator.doWait() | 1 | 2 | 2 |
elevatorsystem.elevator.Elevator.elevatorStop() | 1 | 6 | 11 |
elevatorsystem.elevator.Elevator.getArrival() | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.getDirection() | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.getFloor() | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.getNextRequest() | 1 | 4 | 4 |
elevatorsystem.elevator.Elevator.getRequestNum() | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.getRunning() | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.getStatus() | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.isDown(PersonRequest) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.isUp(PersonRequest) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.load() | 1 | 6 | 6 |
elevatorsystem.elevator.Elevator.lookDown() | 4 | 2 | 4 |
elevatorsystem.elevator.Elevator.lookUp() | 4 | 2 | 4 |
elevatorsystem.elevator.Elevator.moveDown() | 1 | 2 | 3 |
elevatorsystem.elevator.Elevator.moveUp() | 1 | 2 | 3 |
elevatorsystem.elevator.Elevator.open() | 1 | 2 | 2 |
elevatorsystem.elevator.Elevator.run() | 6 | 16 | 17 |
elevatorsystem.elevator.Elevator.setArrival(ArrayList
|
1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setDirection(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setFloor(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setInf(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setRequestNum(Integer) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setRunning(Boolean) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setStatus(Integer,ArrayList
|
1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setSup(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.unload() | 1 | 3 | 3 |
elevatorsystem.elevator.ElevatorBuild.InitOne() | 3 | 2 | 3 |
elevatorsystem.elevator.ElevatorBuild.getElevatorBuild() | 1 | 1 | 3 |
elevatorsystem.elevator.ElevatorBuild.getElevatorOne() | 1 | 1 | 1 |
elevatorsystem.elevator.ElevatorBuild.run() | 1 | 1 | 1 |
Class | OCavg | WMC | |
Main | 1 | 1 | |
elevatorsystem.RequestInput | 2 | 4 | |
elevatorsystem.Scheduler | 1.67 | 5 | |
elevatorsystem.elevator.Elevator | 2.17 | 65 | |
elevatorsystem.elevator.ElevatorBuild | 2 | 8 |
不出所料,仍然是Elevator的運行方法和每層樓的接送乘客方法複雜度較高。
筆者的設計符合SRP原則,輸入類只負責輸入,電梯的Builder類只負責生成電梯,電梯只負責運行已收到的請求,調度器只負責將收到的請求分給電梯。
筆者在此次做業中充分考慮了向多電梯的可擴展性,新增ElevatorBuild類,負責根據不一樣參數生成不一樣種類的電梯,因此這個架構在第三次做業中得以沿用。
筆者的程序在公測中未被發現bug。
筆者的程序在互測中未被發現bug。筆者發現其餘同窗的一個bug,在某種狀況下,他的電梯會一直向上或向下運行而不會停下(所謂的飛天遁地),緣由應該是對邊界樓層和電梯轉向的處理不嚴密。
筆者沿用了第一次做業的測試工具,定時投放+輸出數據正確性檢測。
最後一次做業增長了多電梯(3個),而且每一個電梯的可到達樓層不一樣,須要考慮換乘的狀況,總體難度較大,而且對線程穩定性的要求也很高。筆者的設計是採用三臺Look調度算法的電梯,每一個電梯只負責本身請求隊列裏的指令,須要換乘的指令會在指令輸入的時候被拆分紅兩條指令,在第一條指令執行完畢後將第二條指令加入請求隊列。
能夠看到,對於筆者的架構,從第二次做業到第三次做業,幾乎只須要修改調度器,其餘部分不作改動,因此筆者此次做業完成地也比較輕鬆。
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
Main.main(String[]) | 1 | 1 | 1 |
elevatorsystem.RequestInput.RequestInput(Scheduler) | 1 | 1 | 1 |
elevatorsystem.RequestInput.run() | 3 | 4 | 4 |
elevatorsystem.Scheduler.InitChange(ArrayList<ArrayList
|
1 | 2 | 2 |
elevatorsystem.Scheduler.Scheduler() | 1 | 1 | 1 |
elevatorsystem.Scheduler.addRequest(PersonRequest) | 1 | 10 | 10 |
elevatorsystem.Scheduler.checkStatus(char,ArrayList
|
6 | 9 | 9 |
elevatorsystem.Scheduler.createMapA() | 1 | 5 | 10 |
elevatorsystem.Scheduler.createMapB() | 1 | 5 | 8 |
elevatorsystem.Scheduler.createMapC() | 1 | 5 | 6 |
elevatorsystem.Scheduler.doWait(Object) | 1 | 2 | 2 |
elevatorsystem.Scheduler.getChange() | 1 | 1 | 1 |
elevatorsystem.Scheduler.getLock() | 1 | 1 | 1 |
elevatorsystem.Scheduler.getMap(char) | 3 | 1 | 3 |
elevatorsystem.Scheduler.getQueue(char) | 3 | 1 | 3 |
elevatorsystem.Scheduler.getRequestNum(char) | 3 | 1 | 3 |
elevatorsystem.Scheduler.getRunning() | 1 | 1 | 1 |
elevatorsystem.Scheduler.getScheduler() | 1 | 1 | 3 |
elevatorsystem.Scheduler.lock() | 1 | 1 | 1 |
elevatorsystem.Scheduler.mapInit(HashMap<Integer, ArrayList
|
3 | 2 | 3 |
elevatorsystem.Scheduler.removeRequest(PersonRequest) | 1 | 1 | 4 |
elevatorsystem.Scheduler.requestMapInit(HashMap<Integer, ArrayList
|
3 | 2 | 3 |
elevatorsystem.Scheduler.setRunning(Boolean) | 1 | 1 | 1 |
elevatorsystem.Scheduler.takeApart(PersonRequest) | 1 | 10 | 10 |
elevatorsystem.Scheduler.unLock() | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.Elevator(Scheduler,Object) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.addAvailableFloor(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.check() | 1 | 7 | 9 |
elevatorsystem.elevator.Elevator.close() | 1 | 2 | 2 |
elevatorsystem.elevator.Elevator.doWait(Object) | 1 | 2 | 2 |
elevatorsystem.elevator.Elevator.elevatorStop() | 1 | 5 | 10 |
elevatorsystem.elevator.Elevator.getArrival() | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.getDirection() | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.getFloor() | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.getNextRequest() | 1 | 4 | 4 |
elevatorsystem.elevator.Elevator.isDown(PersonRequest) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.isUp(PersonRequest) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.load() | 3 | 6 | 7 |
elevatorsystem.elevator.Elevator.lookDown() | 4 | 2 | 4 |
elevatorsystem.elevator.Elevator.lookUp() | 4 | 2 | 4 |
elevatorsystem.elevator.Elevator.moveDown() | 1 | 2 | 3 |
elevatorsystem.elevator.Elevator.moveUp() | 1 | 2 | 3 |
elevatorsystem.elevator.Elevator.open() | 1 | 2 | 2 |
elevatorsystem.elevator.Elevator.run() | 6 | 17 | 19 |
elevatorsystem.elevator.Elevator.setArrival(ArrayList
|
1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setDirection(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setFloor(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setInf(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setMaxContain(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setMoveTime(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setName(char) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setOpenTime(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.setSup(int) | 1 | 1 | 1 |
elevatorsystem.elevator.Elevator.unload() | 1 | 7 | 8 |
elevatorsystem.elevator.ElevatorBuild.ElevatorBuild(Scheduler) | 1 | 1 | 1 |
elevatorsystem.elevator.ElevatorBuild.InitA() | 1 | 3 | 5 |
elevatorsystem.elevator.ElevatorBuild.InitB() | 1 | 3 | 4 |
elevatorsystem.elevator.ElevatorBuild.InitC() | 1 | 3 | 3 |
elevatorsystem.elevator.ElevatorBuild.getElevatorA() | 1 | 1 | 1 |
elevatorsystem.elevator.ElevatorBuild.getElevatorB() | 1 | 1 | 1 |
elevatorsystem.elevator.ElevatorBuild.getElevatorBuild(Scheduler) | 1 | 1 | 3 |
elevatorsystem.elevator.ElevatorBuild.getElevatorC() | 1 | 1 | 1 |
elevatorsystem.elevator.ElevatorBuild.run() | 1 | 1 | 1 |
Class | OCavg | WMC | |
Main | 1 | 1 | |
elevatorsystem.RequestInput | 2 | 4 | |
elevatorsystem.Scheduler | 3.14 | 69 | |
elevatorsystem.elevator.Elevator | 2.45 | 71 | |
elevatorsystem.elevator.ElevatorBuild | 1.89 | 17 |
能夠看到,調度器的添加請求方法和拆分請求方法,以及電梯的run方法複雜度很高。結合代碼不難看出複雜度高的緣由。調度器的添加請求方法須要作這麼幾件事:
這其中有很複雜的條件語句,因此方法複雜度略高。
至於電梯的run方法,是負責整個電梯運行邏輯的,因此複雜度略高也合乎情理。
筆者的設計符合SRP原則,輸入類只負責輸入,電梯的Builder類只負責生成電梯,電梯只負責運行已收到的請求,調度器只負責接收和拆分請求,並分配給不一樣的電梯。
筆者在此次做業中保留了對更多電梯的可擴展性,經過ElevatorBuild類可進行擴展。可是本次做業個人調度器是每一個電梯一個請求隊列,因此擴展起來比較麻煩,我想若是設計成全部電梯共用一個請求隊列的話,應該會更加便於擴展。
本次公測筆者的程序炸了不少點,緣由是有一個條件語句加錯了位置,更改後可穩定經過所有測試點。
筆者找到其餘同窗不少bug,有程序沒法結束的,有電梯超載的,有運行時間過長的,還有乘客未送到指定位置的。畢竟是C組,這麼多bug也就不足爲奇了。
多線程設計讓我明白瞭如下幾點:
但願在之後的學習中,我能夠更好地掌握測試方法,寫出更加完美的程序。