java混沌之源——多線程的名氣早有耳聞,第一次寫具備必定規模的多線程代碼仍是挺刺激的。html
不過,因爲以前長期考慮過多線程電梯的架構,這三次雖然寫得很絕望,性能分也不算高,但多少java
仍是沒被測出Bug,這一點實屬幸運。git
接下來就主要談談三次做業本身的一些設計思路以及優化思路,順便談談本身搭評測姬遇到的一些坑點。github
前排感謝 lsj、wsb、shh、xcb四位巨巨(排序由隨機函數生成)算法
這裏,爲了觀看體驗,我把方法以及變量隱去了。ubuntu
Dispatcher
線程負責和電梯的控制器線程(Scheduler
)直接交互,Dispatcher
把Main
傳入的請求分配給電梯的控制器。電梯的控制器週期性甦醒,檢查本身的任務列表,對電梯發出指令。性能優化
此外,GlobalPermission
和DispatcherClose
是兩個用於控制進程結束的對象。多線程
public enum ElevatorOrder { GO_UP,GO_DOWN,STAY_IDLE,OPEN_DOOR,CLOSE_DOOR }
Elevator
的工做機制是這樣的,每個最小時間週期甦醒一次,這表明上一個週期scheduler
給電梯下達的指令,電梯已經完成。此時電梯須要向電梯發送本身最新的狀態報告,以後根據自身已獲得的任務做出下一個週期的指令,並進入執行狀態(sleep)架構
Dispatcher
經過blockqueue
來查詢電梯的狀態,即,只有每個電梯都給分配器發送了本身最新狀態的報告,分配器纔會認爲此時獲得的電梯信息足夠新鮮,能夠做爲任務分配依據,纔會給各個電梯進行任務分配。ide
後來在實踐中,筆者認識到,這個架構極其 愚蠢 ,緣由以下
dispatcher
收集到足夠信息剛剛要分配任務時,電梯已經完成了任務檢查,那麼,這個報告機制失去了它的意義。dispatcher
線程結束,那麼,dispatcher
就可能陷入死等報告的狀態,沒法結束。這要求,咱們必須保證dispatcher
線程先於電梯線程結束,這就是爲何,個人設計裏有一個突兀的DispatcherClose
類。Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
elevator.Dispatcher.Dispatcher(int,ArrayList<>,Permission,Close) | 1 | 1 | 1 |
elevator.Dispatcher.dispatch() | 1 | 2 | 2 |
elevator.Dispatcher.getNewRequests() | 1 | 1 | 1 |
elevator.Dispatcher.hasWork() | 1 | 2 | 2 |
elevator.Dispatcher.run() | 1 | 4 | 4 |
elevator.Dispatcher.updateReports() | 1 | 2 | 2 |
elevator.Dispatcher.updateRequests() | 1 | 1 | 1 |
elevator.DispatcherClose.close() | 1 | 1 | 1 |
elevator.DispatcherClose.isClosed() | 1 | 1 | 1 |
elevator.Elevator.Elevator(int) | 1 | 1 | 1 |
elevator.Elevator.executeOrder() | 12 | 11 | 16 |
elevator.Elevator.getRecord() | 1 | 1 | 1 |
elevator.Elevator.getState() | 1 | 1 | 1 |
elevator.Elevator.isInteger(BigDecimal) | 1 | 1 | 1 |
elevator.Elevator.setOrder(ElevatorOrder) | 1 | 1 | 1 |
elevator.ElevatorRecord.ElevatorRecord(int,BigDecimal) | 1 | 1 | 1 |
elevator.ElevatorRecord.getMileage() | 1 | 1 | 1 |
elevator.ElevatorState.ElevatorState(BigDecimal,boolean,ElevatorOrder) | 1 | 1 | 1 |
elevator.ElevatorState.getDoorOpen() | 1 | 1 | 1 |
elevator.ElevatorState.getFloor() | 1 | 1 | 1 |
elevator.ElevatorState.getToDo() | 1 | 1 | 1 |
elevator.ElevatorState.toString() | 1 | 1 | 1 |
elevator.GlobalPermission.forbid() | 1 | 1 | 1 |
elevator.GlobalPermission.getPermitted() | 1 | 1 | 1 |
elevator.Main.main(String[]) | 3 | 4 | 4 |
elevator.Scheduler.Scheduler(int,GlobalPermission,DispatcherClose) | 1 | 1 | 1 |
elevator.Scheduler.getDispatchedRequests() | 1 | 1 | 1 |
elevator.Scheduler.getNewRequests() | 1 | 1 | 1 |
elevator.Scheduler.getReportBox() | 1 | 1 | 1 |
elevator.Scheduler.hasWork() | 1 | 3 | 3 |
elevator.Scheduler.meetRequest() | 1 | 3 | 4 |
elevator.Scheduler.pickRequest() | 1 | 3 | 4 |
elevator.Scheduler.run() | 1 | 5 | 5 |
elevator.Scheduler.schedule() | 6 | 4 | 6 |
elevator.Scheduler.sendOrder(ElevatorOrder) | 1 | 1 | 1 |
elevator.Scheduler.sendReport() | 1 | 1 | 1 |
elevator.Sleeper.sleep(long) | 1 | 3 | 3 |
Class | OCavg | WMC | |
elevator.Dispatcher | 1.43 | 10 | |
elevator.DispatcherClose | 1 | 2 | |
elevator.Elevator | 3 | 18 | |
elevator.ElevatorOrder | n/a | 0 | |
elevator.ElevatorRecord | 1 | 2 | |
elevator.ElevatorState | 1 | 5 | |
elevator.GlobalPermission | 1 | 2 | |
elevator.Main | 3 | 3 | |
elevator.Scheduler | 1.91 | 21 | |
elevator.Sleeper | 3 | 3 | |
Package | v(G)avg | v(G)tot | |
elevator | 2.16 | 80 | |
Module | v(G)avg | v(G)tot | |
P5 | 2.16 | 80 | |
Project | v(G)avg | v(G)tot | |
project | 2.16 | 80 |
能夠看出,筆者的此次,由於業務邏輯較爲簡單,沒有出現業務邏輯過於密集的類,可是由於對於電梯控制缺少經驗,與產生電梯指令,執行電梯指令相關的
elevator.Scheduler.schedule()
和elevator.Elevator.executeOrder()
兩個方法的複雜度有點太高。
本次做業功能較爲簡單,本人的重點放在了線程協做架構的可拓展性上了,對於功能的拓展並未作過多深刻,故沒法提現SOLID原則,其中因爲Shceduler
類完成了發送報告的工做,違反了SPR原則。
本次的測試不管是本身測本身仍是測別人都與前幾回做業有很大不一樣,關於評測姬的搭建,筆者將其放到文末,此處僅僅簡要報告測試狀況。
本人在自測階段發現了本身前文所述若是線程退出順序不對,出現沒法結束程序的問題。其它問題,並無出現。
因爲業務邏輯簡單,故你們都開心無傷過。
順便%一下shh的23行單線程解決問題的代碼,orz
本次做業因爲引入了地下樓層這個神奇的機制,因而我依據wsb巨巨的建議設置了樓層類,並經過軌道類來管理樓層類。電梯以及其控制器保存同一個Rail(軌道)對象,用於實現與樓層編號相關的計算與轉換。此外,此次設計放棄了發送報告的機制,採用ElevatorStatusBuffer
做爲電梯把本身信息提供給Dispatcher
的中轉站。
Dispatcher
的交互Dispatcher
與Elevator
的交互本次個人線程寫做關係受到了OS課程的啓發
如下文段出自OS指導書
用戶態和內核態的概念相信你們也不陌生,內核態即計組實驗中所提到的特權態,用戶態就是非特權態。mips 彙編中使用一些特權指令如mtc0、mfc0、syscall等都會陷入特權態(內核態)。
而咱們此次實驗,根據./include/mmu.h裏面的佈局來講,咱們是2G/2G 模式,用戶態佔用2G,內核態佔用2G。接下來,也是最容易產生混淆的地方,進程從用戶態提高到內核態的過程,操做系統中發生了什麼?
是從當前進程切換成一個所謂的「內核進程」來管理一切了嗎?不!仍是同樣的配方,仍是同樣的進程!改變的其實只是進程的權限!咱們打一個比方,你所在的班級裏沒有班長,任何人均可以以合理的理由到老師那申請當臨時班長。你是班裏的成員嗎?固然是的。某天你申請當臨時班長,申請成功了,那麼如今你仍是班裏的成員嗎?固然仍是的。那麼你先後有什麼區別呢?是權限的變化。可能你以前和其餘成員是徹底平等,互不干涉的。那麼如今你能夠根據花名冊點名,你能夠安排班裏的成員作些事情,你能夠開班長會議等等。那麼咱們能說你是班長嗎?不能,由於你並非永久的班長。但能說你擁有成爲班長的資格嗎?固然能夠,這種成爲臨時班長的資格,咱們能夠粗略地認爲它就是內核態的精髓所在。
而在操做系統中,每一個完整的進程都擁有這種成爲臨時內核的資格,即全部的進程均可以發出申請變成內核態下運行的進程。內核態下進程可訪問的資源更多,更加自由。在以後咱們會提到一種「申請」的方式,就叫作「系統調用」。
我把Dispatcher
視爲內核,只有一個線程搶到了內核權限,它纔可以更新所有電梯在Dispatcher
記錄的狀態,並給各個電梯(包括非「內核態」下的本身)分配任務。
如今看來,個人這個設計有一個問題,若是此時有多部電梯,那麼電梯A退出內核態到更新ElevatorStatusBuffer
的時間間隙另外一個電梯B進入內核態開始查詢狀態,可能會出如今B分配任務的時候,利用的是一個已通過時的狀態,這個問題雖然不必定影響正確性但在某些邊界條件下可能會影響性能。
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
ElevatorSystem.main(String[]) | 3 | 5 | 5 |
dispatcher.Dispatcher.Dispatcher(Rail,GlobalPermission) | 1 | 1 | 1 |
dispatcher.Dispatcher.addAlsElevator() | 1 | 1 | 1 |
dispatcher.Dispatcher.addLookElevator() | 1 | 1 | 1 |
dispatcher.Dispatcher.addNaiveElevator() | 1 | 1 | 1 |
dispatcher.Dispatcher.addSillyElevator() | 1 | 1 | 1 |
dispatcher.Dispatcher.dispatchRequests() | 1 | 4 | 4 |
dispatcher.Dispatcher.getBuffer() | 1 | 1 | 1 |
dispatcher.Dispatcher.getElevators() | 1 | 1 | 1 |
dispatcher.Dispatcher.hasMoreWork() | 1 | 3 | 3 |
dispatcher.Dispatcher.setElevators(ArrayList
|
1 | 1 | 1 |
dispatcher.Dispatcher.updateRequests() | 1 | 1 | 1 |
elevator.Elevator.Elevator(int,Rail,SchedulerType,Dispatcher) | 2 | 2 | 6 |
elevator.Elevator.closeDoor() | 1 | 2 | 2 |
elevator.Elevator.executeOrder(ElevatorOrder) | 2 | 7 | 7 |
elevator.Elevator.getDispatcher() | 1 | 1 | 1 |
elevator.Elevator.getHelper() | 1 | 1 | 1 |
elevator.Elevator.getOrderAndUpdateBuffer() | 1 | 1 | 1 |
elevator.Elevator.getRail() | 1 | 1 | 1 |
elevator.Elevator.getScheduler() | 1 | 1 | 1 |
elevator.Elevator.getStatus() | 1 | 1 | 1 |
elevator.Elevator.getStatusBuffer() | 1 | 1 | 1 |
elevator.Elevator.hasMoreWork() | 1 | 1 | 1 |
elevator.Elevator.openDoor() | 1 | 2 | 2 |
elevator.Elevator.run() | 1 | 2 | 2 |
elevator.Elevator.servePassengers() | 1 | 2 | 2 |
elevator.Elevator.updateStatusBuffer(ElevatorOrder) | 2 | 2 | 6 |
elevator.ElevatorFactory.ElevatorFactory(Rail,Dispatcher) | 1 | 1 | 1 |
elevator.ElevatorFactory.produceAlsElevator() | 1 | 1 | 1 |
elevator.ElevatorFactory.produceLookElevator() | 1 | 1 | 1 |
elevator.ElevatorFactory.produceNaiveElevator() | 1 | 1 | 1 |
elevator.ElevatorFactory.produceSillyElevator() | 1 | 1 | 1 |
elevator.ElevatorStatus.ElevatorStatus(int,int,int,boolean,ElevatorOrder) | 1 | 1 | 1 |
elevator.ElevatorStatus.getExecutingOrder() | 1 | 1 | 1 |
elevator.ElevatorStatus.getFloorIndex() | 1 | 1 | 1 |
elevator.ElevatorStatus.getMileage() | 1 | 1 | 1 |
elevator.ElevatorStatusBuffer.ElevatorStatusBuffer(ElevatorStatus) | 1 | 1 | 1 |
elevator.ElevatorStatusBuffer.getStatus() | 1 | 1 | 1 |
elevator.ElevatorStatusBuffer.setStatus(ElevatorStatus) | 1 | 1 | 1 |
exception.FloorIdException.FloorIdException(int) | 1 | 1 | 1 |
floor.Floor.Floor(int) | 1 | 1 | 1 |
floor.Floor.getId() | 1 | 1 | 1 |
floor.Rail.Rail(int,int) | 1 | 1 | 3 |
floor.Rail.getFloorId(int) | 1 | 1 | 1 |
floor.Rail.getFromFloorIndex(PersonRequest) | 1 | 2 | 2 |
floor.Rail.getIndex(int) | 3 | 1 | 5 |
floor.Rail.getToFloorIndex(PersonRequest) | 1 | 2 | 2 |
scheduler.AlsSchedule.AlsSchedule(Elevator) | 1 | 1 | 1 |
scheduler.AlsSchedule.canGetOut(MarkRequest) | 2 | 2 | 3 |
scheduler.AlsSchedule.canPick(MarkRequest) | 3 | 3 | 5 |
scheduler.AlsSchedule.dispatchRequest(PersonRequest) | 1 | 1 | 1 |
scheduler.AlsSchedule.getOrder() | 7 | 2 | 7 |
scheduler.AlsSchedule.hasMoreWork() | 1 | 3 | 3 |
scheduler.AlsSchedule.isNeedServe() | 5 | 3 | 5 |
scheduler.AlsSchedule.meetPassengers() | 1 | 3 | 4 |
scheduler.AlsSchedule.passengersServe() | 1 | 1 | 1 |
scheduler.AlsSchedule.pickPassengers() | 1 | 3 | 3 |
scheduler.AlsSchedule.toString() | 1 | 1 | 1 |
scheduler.AlsSchedule.updateMainRequest() | 2 | 3 | 4 |
scheduler.LookScheduler.LookScheduler(Elevator) | 1 | 1 | 1 |
scheduler.LookScheduler.canGetOut(MarkRequest) | 2 | 2 | 3 |
scheduler.LookScheduler.canPick(MarkRequest) | 8 | 10 | 16 |
scheduler.LookScheduler.cntNeedDown() | 1 | 2 | 3 |
scheduler.LookScheduler.cntNeedUp() | 1 | 2 | 3 |
scheduler.LookScheduler.dispatchRequest(PersonRequest) | 1 | 1 | 1 |
scheduler.LookScheduler.getOrder() | 12 | 2 | 12 |
scheduler.LookScheduler.hasMoreWork() | 1 | 2 | 2 |
scheduler.LookScheduler.isNeedServe() | 5 | 3 | 5 |
scheduler.LookScheduler.passengersServe() | 1 | 4 | 4 |
scheduler.LookScheduler.toString() | 1 | 1 | 1 |
scheduler.MarkRequest.MarkRequest(Rail,PersonRequest) | 1 | 1 | 3 |
scheduler.MarkRequest.equals(Object) | 3 | 1 | 3 |
scheduler.MarkRequest.getDirection() | 1 | 1 | 1 |
scheduler.MarkRequest.getFromFloorIndex() | 1 | 1 | 1 |
scheduler.MarkRequest.getNowNeedDirection(int) | 3 | 1 | 3 |
scheduler.MarkRequest.getPersonId() | 1 | 1 | 1 |
scheduler.MarkRequest.getPersonRequest() | 1 | 1 | 1 |
scheduler.MarkRequest.getTargetIndex() | 2 | 2 | 2 |
scheduler.MarkRequest.getToFloorIndex() | 1 | 1 | 1 |
scheduler.MarkRequest.isPicked() | 1 | 1 | 1 |
scheduler.MarkRequest.pick() | 1 | 1 | 1 |
scheduler.NaiveScheduler.NaiveScheduler(Elevator) | 1 | 1 | 1 |
scheduler.NaiveScheduler.dispatchRequest(PersonRequest) | 1 | 1 | 1 |
scheduler.NaiveScheduler.getOrder() | 7 | 3 | 7 |
scheduler.NaiveScheduler.hasMoreWork() | 1 | 3 | 3 |
scheduler.NaiveScheduler.meetRequests() | 1 | 3 | 3 |
scheduler.NaiveScheduler.passengersServe() | 1 | 1 | 1 |
scheduler.NaiveScheduler.pickPassengers() | 1 | 3 | 3 |
scheduler.NaiveScheduler.toString() | 1 | 1 | 1 |
scheduler.RunTarget.RunTarget(int,Direction) | 1 | 1 | 1 |
scheduler.RunTarget.getRunDirection() | 1 | 1 | 1 |
scheduler.RunTarget.getTargetIndex() | 1 | 1 | 1 |
scheduler.RunTarget.toString() | 1 | 1 | 1 |
scheduler.SillyScheduler.SillyScheduler(Elevator) | 1 | 1 | 1 |
scheduler.SillyScheduler.canGetOut(MarkRequest) | 2 | 2 | 3 |
scheduler.SillyScheduler.canPick(MarkRequest) | 7 | 5 | 10 |
scheduler.SillyScheduler.dispatchRequest(PersonRequest) | 1 | 1 | 1 |
scheduler.SillyScheduler.getDistance(MarkRequest) | 1 | 1 | 1 |
scheduler.SillyScheduler.getOrder() | 5 | 1 | 5 |
scheduler.SillyScheduler.getRunDirection(MarkRequest) | 3 | 1 | 3 |
scheduler.SillyScheduler.hasMoreWork() | 1 | 2 | 2 |
scheduler.SillyScheduler.isNeedServe() | 5 | 3 | 5 |
scheduler.SillyScheduler.passengersServe() | 1 | 5 | 6 |
scheduler.SillyScheduler.selectMaintarget(int,int,int,int,int) | 8 | 8 | 12 |
scheduler.SillyScheduler.setMainTarget(int,Direction) | 1 | 1 | 1 |
scheduler.SillyScheduler.toString() | 1 | 1 | 1 |
scheduler.SillyScheduler.updateMainTarget() | 5 | 4 | 7 |
tools.GlobalPermission.isSystemContinue() | 1 | 1 | 1 |
tools.GlobalPermission.systemQuit() | 1 | 1 | 1 |
tools.GlobalPermission.systemStart() | 1 | 1 | 1 |
tools.OutputHelper.finalOutput() | 1 | 2 | 2 |
tools.OutputHelper.output(OutputHelper) | 1 | 2 | 2 |
tools.OutputHelper.println(String) | 1 | 1 | 1 |
tools.TimeManager.idleSleep() | 1 | 2 | 3 |
tools.TimeManager.moveSleep() | 1 | 2 | 3 |
tools.TimeManager.serveSleep() | 1 | 2 | 3 |
Class | OCavg | WMC | |
ElevatorSystem | 3 | 3 | |
dispatcher.Dispatcher | 1.18 | 13 | |
elevator.Elevator | 2.2 | 33 | |
elevator.ElevatorFactory | 1 | 5 | |
elevator.ElevatorOrder | n/a | 0 | |
elevator.ElevatorStatus | 1 | 4 | |
elevator.ElevatorStatusBuffer | 1 | 3 | |
exception.FloorIdException | 1 | 1 | |
floor.Floor | 1 | 2 | |
floor.Rail | 1.8 | 9 | |
scheduler.AlsSchedule | 2.75 | 33 | |
scheduler.LookScheduler | 3.73 | 41 | |
scheduler.MarkRequest | 1.64 | 18 | |
scheduler.NaiveScheduler | 2.25 | 18 | |
scheduler.RunTarget | 1 | 4 | |
scheduler.SchedulerType | n/a | 0 | |
scheduler.SillyScheduler | 3.57 | 50 | |
tools.Direction | n/a | 0 | |
tools.GlobalPermission | 1 | 3 | |
tools.OutputHelper | 1.67 | 5 | |
tools.TimeManager | 2 | 6 | |
Package | v(G)avg | v(G)tot | |
5 | 5 | ||
dispatcher | 1.45 | 16 | |
elevator | 1.74 | 47 | |
exception | 1 | 1 | |
floor | 2.14 | 15 | |
scheduler | 3.15 | 189 | |
tools | 1.89 | 17 | |
Module | v(G)avg | v(G)tot | |
Project6 | 2.5 | 290 | |
Project | v(G)avg | v(G)tot | |
project | 2.5 | 290 |
通過分析能夠發現,方法的複雜性依舊體如今調度算法的實現上,這一類方法始終是複雜度最高的方法。
此外這次做業中電梯類的設計耦合度太高,主要是由於我在設計構造方法的時候欠考慮了,致使電梯的構造與管理很是混亂。
單一責任原則:
刪去了Scheduler
的發送報告方法,使其功能更加單一——根據請求與電梯狀態控制電梯行爲
開放封閉原則
個人Rail
,Floor
支持擴展,且沒必要修改任何原有的功能方法,而且在第三次做業中獲得了應用,這兩個類符合開閉原則。
里氏替換原則
本次設計本人未使用繼承操做,故不涉及。
依賴倒置原則
本次做業本人採用了多種電梯的控制策略,都採用了Scheduler
這一接口,同時他們的實現各有特色。
接口分離原則
此次的設計僅僅使用了Scheduler
這惟一的接口,且都是有必要的方法,故不涉及。
本人此次的Look
算法有很嚴重的Bug:若是此時電梯處於Idle狀態,且上下同時各自來一個請求,且無後續請求,那麼電梯將卡死不動。可是,這個Bug被個人奇技淫巧優化給巧妙地迴避了。因此在強測和互測都沒有翻車。
此次同屋神仙有丶多,代碼風格好看,命名規範,算法強大,鄙人才學疏淺實在找不出問題。
本次做業中,我給Floor
加入了訪問權限這一設定,每一部電梯經過本身私有的Rail
能夠查詢本身是否有權限在當前樓層停靠。爲了便於實現換乘的功能,我引入了TemRequest
這個概念(爲了保證類圖的簡潔直觀,並未在圖中體現),這類對象的做用在於,劃分行動路徑,把難以一步到位的請求分割成多個可一步到位的請求,把這些能夠一步到位的請求稱之爲TemRequest
。本次設計中,我引入了Person
類,其保存了乘客的樓層位置信息
、TemRequest
、請求是否分配給電梯
等信息。前文提到,咱們須要實現對請求
的分割,RequestDivider
所完成的便是這一工做。至於識別請求
能否一步到位,這個任務交給了RegionJudger
來完成。其他部分與第六次做業設計相似,故不贅述。
Dispatcher
的交互Dispatcher
與Elevator
的交互本次設計我沿用了第六次做業的內核態模式,不過更加「集權」。這次設計中,各個線程在沒有Dispatcher
權限的時候,甚至沒法給本身下達指令,沒法改變本身的狀態。這麼設計看似有丶違背常理,可是這麼作有一個好處,我能夠保證線程在Dispatcher
權限下查詢到的各個電梯的信息,在完成這次任務分配時都必定時有效的信息,即,與此時各個電梯的狀態徹底一致。
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
ElevatorSystem.main(String[]) | 3 | 6 | 6 |
algorithm.Allocater.Allocater(RegionJudger) | 1 | 1 | 1 |
algorithm.Allocater.canByTheWay(int,Direction,PersonRequest) | 3 | 3 | 7 |
algorithm.Allocater.selectAb(PersonRequest) | 4 | 2 | 6 |
algorithm.Allocater.selectAbc(PersonRequest) | 11 | 1 | 20 |
algorithm.Allocater.selectBc(PersonRequest) | 6 | 3 | 6 |
algorithm.Allocater.selectElevatorAllocate(Person,Status,Status,Status) | 8 | 5 | 8 |
algorithm.Allocater.updateValue(Request,Status,Status,Status) | 1 | 1 | 1 |
algorithm.RegionJudger.ACanSolo(PersonRequest) | 1 | 2 | 2 |
algorithm.RegionJudger.BCanSolo(PersonRequest) | 1 | 2 | 2 |
algorithm.RegionJudger.CCanSolo(PersonRequest) | 1 | 2 | 2 |
algorithm.RegionJudger.RegionJudger(Rail,Rail,Rail) | 1 | 1 | 1 |
algorithm.RegionJudger.canSolo(PersonRequest) | 1 | 3 | 3 |
algorithm.RegionJudger.floorIndexInAHighRegion(int) | 1 | 2 | 2 |
algorithm.RegionJudger.floorIndexInALowRegion(int) | 1 | 1 | 2 |
algorithm.RegionJudger.fromARegion(PersonRequest) | 1 | 1 | 1 |
algorithm.RegionJudger.fromBRegion(PersonRequest) | 1 | 1 | 1 |
algorithm.RegionJudger.fromCRegion(PersonRequest) | 1 | 1 | 1 |
algorithm.RegionJudger.getCanTakeMode(PersonRequest) | 6 | 5 | 10 |
algorithm.RegionJudger.inHighRegionA(PersonRequest) | 1 | 2 | 2 |
algorithm.RegionJudger.inLowRegionA(PersonRequest) | 1 | 2 | 2 |
algorithm.RegionJudger.onlyACanSolo(PersonRequest) | 1 | 3 | 3 |
algorithm.RegionJudger.toARegion(PersonRequest) | 1 | 1 | 1 |
algorithm.RegionJudger.toBRegion(PersonRequest) | 1 | 1 | 1 |
algorithm.RegionJudger.toCRegion(PersonRequest) | 1 | 1 | 1 |
algorithm.RequestDivider.RequestDivider(Rail,Rail,Rail,RegionJudger) | 1 | 1 | 1 |
algorithm.RequestDivider.setPersonTemRequest(Person) | 14 | 15 | 16 |
algorithm.RequestDivider.setPersonTemRequest1(Person) | 13 | 12 | 13 |
algorithm.RequestDivider.setTemRequest(Person,int,int) | 1 | 1 | 1 |
dispatcher.Dispatcher.Dispatcher(GlobalPermission) | 1 | 1 | 1 |
dispatcher.Dispatcher.allocatePerson() | 1 | 5 | 5 |
dispatcher.Dispatcher.allocatePersonToElevator(Person,int) | 1 | 1 | 3 |
dispatcher.Dispatcher.checkPersonArriveDestination() | 4 | 2 | 4 |
dispatcher.Dispatcher.dispatch() | 1 | 1 | 1 |
dispatcher.Dispatcher.getBuffer() | 1 | 1 | 1 |
dispatcher.Dispatcher.getElevators() | 1 | 1 | 1 |
dispatcher.Dispatcher.getNewInputRequests() | 1 | 2 | 2 |
dispatcher.Dispatcher.getPersonById(int) | 3 | 2 | 3 |
dispatcher.Dispatcher.hasMoreWork() | 1 | 3 | 3 |
dispatcher.Dispatcher.passengersIn(ArrayList
|
1 | 2 | 2 |
dispatcher.Dispatcher.passengersOut(ArrayList
|
1 | 2 | 2 |
dispatcher.Dispatcher.personIn(Person,int,int) | 1 | 1 | 3 |
dispatcher.Dispatcher.personOut(Person,int) | 1 | 1 | 1 |
dispatcher.Dispatcher.update() | 1 | 1 | 1 |
dispatcher.Dispatcher.updateElevatorStatus() | 1 | 1 | 1 |
dispatcher.Dispatcher.updatePersonFloor() | 2 | 6 | 7 |
dispatcher.Dispatcher.updateRequestsDivision() | 1 | 2 | 2 |
elevator.Elevator.Elevator(String,int,Rail,Dispatcher,Timer,Type) | 2 | 2 | 5 |
elevator.Elevator.closeDoor() | 1 | 2 | 2 |
elevator.Elevator.dispatchRequest(PersonRequest) | 1 | 1 | 1 |
elevator.Elevator.executeOrder(ElevatorOrder) | 2 | 5 | 5 |
elevator.Elevator.getCapacity() | 1 | 1 | 1 |
elevator.Elevator.getDispatcher() | 1 | 1 | 1 |
elevator.Elevator.getName() | 1 | 1 | 1 |
elevator.Elevator.getOrderAndPresetStatus() | 2 | 3 | 6 |
elevator.Elevator.getRail() | 1 | 1 | 1 |
elevator.Elevator.getStatus() | 1 | 1 | 1 |
elevator.Elevator.isNeedService() | 1 | 1 | 1 |
elevator.Elevator.notServing() | 1 | 1 | 1 |
elevator.Elevator.openDoor() | 1 | 2 | 2 |
elevator.Elevator.run() | 1 | 2 | 2 |
elevator.Elevator.servePassengers() | 1 | 1 | 1 |
elevator.Elevator.willServing() | 1 | 1 | 1 |
elevator.ElevatorStatus.ElevatorStatus(int,int,int,int,int,Direction) | 1 | 1 | 1 |
elevator.ElevatorStatus.getAllocatedNum() | 1 | 1 | 1 |
elevator.ElevatorStatus.getCapacity() | 1 | 1 | 1 |
elevator.ElevatorStatus.getCarryNum() | 1 | 1 | 1 |
elevator.ElevatorStatus.getDirection() | 1 | 1 | 1 |
elevator.ElevatorStatus.getFloorIndex() | 1 | 1 | 1 |
elevator.ElevatorStatus.getId() | 1 | 1 | 1 |
elevator.ElevatorStatus.isFull() | 1 | 1 | 1 |
exception.FloorIdException.FloorIdException(int) | 1 | 1 | 1 |
floor.Floor.Floor(int,boolean) | 1 | 1 | 1 |
floor.Floor.getId() | 1 | 1 | 1 |
floor.Floor.isCanMooring() | 1 | 1 | 1 |
floor.Floor.setPermission(boolean) | 1 | 1 | 1 |
floor.Rail.Rail(int,int) | 1 | 1 | 3 |
floor.Rail.Rail(int,int,int[]) | 1 | 2 | 4 |
floor.Rail.canMooringById(int) | 1 | 1 | 1 |
floor.Rail.canMooringByIndex(int) | 1 | 1 | 1 |
floor.Rail.getFloorId(int) | 1 | 1 | 1 |
floor.Rail.getFloorsSize() | 1 | 1 | 1 |
floor.Rail.getFromFloorIndex(PersonRequest) | 1 | 2 | 2 |
floor.Rail.getIndex(int) | 3 | 4 | 6 |
floor.Rail.getToFloorIndex(PersonRequest) | 1 | 2 | 2 |
person.Person.Person(PersonRequest) | 1 | 1 | 1 |
person.Person.arriveTotalTarget() | 1 | 1 | 1 |
person.Person.getAllocateStatus() | 1 | 1 | 1 |
person.Person.getId() | 1 | 1 | 1 |
person.Person.getLocationId() | 1 | 1 | 1 |
person.Person.getLocationIndex() | 1 | 1 | 1 |
person.Person.getState() | 1 | 1 | 1 |
person.Person.getTargetFloorId() | 1 | 1 | 1 |
person.Person.getTargetFloorIndex() | 1 | 1 | 1 |
person.Person.getTemRequest() | 1 | 1 | 1 |
person.Person.getTotalRequest() | 1 | 1 | 1 |
person.Person.isInA() | 1 | 1 | 1 |
person.Person.isInB() | 1 | 1 | 1 |
person.Person.isInC() | 1 | 1 | 1 |
person.Person.isOutElevator() | 1 | 1 | 1 |
person.Person.setAllocateStatus(AllocateStatus) | 1 | 1 | 1 |
person.Person.setLocationById(int) | 1 | 1 | 1 |
person.Person.setLocationByIndex(int) | 1 | 1 | 1 |
person.Person.setState(PersonState) | 1 | 1 | 1 |
person.Person.setTemRequest(PersonRequest) | 1 | 1 | 1 |
person.Person.toString() | 1 | 1 | 1 |
person.PersonMoveOrder.PersonMoveOrder(MoveOrderType,int) | 1 | 1 | 1 |
person.PersonMoveOrder.getPersonId() | 1 | 1 | 1 |
person.PersonMoveOrder.getType() | 1 | 1 | 1 |
scheduler.MarkRequest.MarkRequest(Rail,PersonRequest) | 1 | 1 | 3 |
scheduler.MarkRequest.equals(Object) | 3 | 1 | 3 |
scheduler.MarkRequest.getDirection() | 1 | 1 | 1 |
scheduler.MarkRequest.getFromFloorIndex() | 1 | 1 | 1 |
scheduler.MarkRequest.getNowNeedDirection(int) | 3 | 1 | 3 |
scheduler.MarkRequest.getPersonId() | 1 | 1 | 1 |
scheduler.MarkRequest.getPersonRequest() | 1 | 1 | 1 |
scheduler.MarkRequest.getTargetIndex() | 2 | 2 | 2 |
scheduler.MarkRequest.getToFloorIndex() | 1 | 1 | 1 |
scheduler.MarkRequest.isPicked() | 1 | 1 | 1 |
scheduler.MarkRequest.pick() | 1 | 1 | 1 |
scheduler.SchedulerForA.SchedulerForA(Elevator) | 1 | 1 | 1 |
scheduler.SchedulerForA.canGetOut(MarkRequest) | 2 | 2 | 3 |
scheduler.SchedulerForA.canPick(MarkRequest) | 10 | 10 | 18 |
scheduler.SchedulerForA.cntNeedDown() | 1 | 4 | 5 |
scheduler.SchedulerForA.cntNeedUp() | 1 | 4 | 5 |
scheduler.SchedulerForA.defaultMode() | 3 | 1 | 3 |
scheduler.SchedulerForA.dispatchRequest(PersonRequest) | 1 | 1 | 1 |
scheduler.SchedulerForA.getCarryNum() | 1 | 1 | 1 |
scheduler.SchedulerForA.getDirection() | 1 | 1 | 1 |
scheduler.SchedulerForA.getOrder() | 18 | 19 | 20 |
scheduler.SchedulerForA.getRequestsNum() | 1 | 1 | 1 |
scheduler.SchedulerForA.isFull() | 1 | 1 | 1 |
scheduler.SchedulerForA.isNeedServe() | 1 | 4 | 4 |
scheduler.SchedulerForA.needGetIn() | 3 | 2 | 3 |
scheduler.SchedulerForA.needGetOut() | 3 | 2 | 3 |
scheduler.SchedulerForA.needReAllocated() | 6 | 5 | 12 |
scheduler.SchedulerForA.passengersGetIn() | 1 | 5 | 5 |
scheduler.SchedulerForA.passengersGetOut() | 1 | 3 | 3 |
scheduler.SchedulerForA.toString() | 1 | 1 | 1 |
scheduler.SchedulerForA.updateMainDirection(Direction) | 3 | 1 | 3 |
scheduler.SchedulerForB.SchedulerForB(Elevator) | 1 | 1 | 1 |
scheduler.SchedulerForB.canGetOut(MarkRequest) | 2 | 2 | 3 |
scheduler.SchedulerForB.canPick(MarkRequest) | 10 | 10 | 18 |
scheduler.SchedulerForB.cntNeedDown() | 1 | 4 | 5 |
scheduler.SchedulerForB.cntNeedUp() | 1 | 4 | 5 |
scheduler.SchedulerForB.defaultMode() | 3 | 1 | 3 |
scheduler.SchedulerForB.dispatchRequest(PersonRequest) | 1 | 1 | 1 |
scheduler.SchedulerForB.getCarryNum() | 1 | 1 | 1 |
scheduler.SchedulerForB.getDirection() | 1 | 1 | 1 |
scheduler.SchedulerForB.getOrder() | 15 | 14 | 15 |
scheduler.SchedulerForB.getRequestsNum() | 1 | 1 | 1 |
scheduler.SchedulerForB.isFull() | 1 | 1 | 1 |
scheduler.SchedulerForB.isNeedServe() | 1 | 4 | 4 |
scheduler.SchedulerForB.needGetIn() | 3 | 2 | 3 |
scheduler.SchedulerForB.needGetOut() | 3 | 2 | 3 |
scheduler.SchedulerForB.needReAllocated() | 6 | 4 | 11 |
scheduler.SchedulerForB.passengersGetIn() | 1 | 5 | 5 |
scheduler.SchedulerForB.passengersGetOut() | 1 | 3 | 3 |
scheduler.SchedulerForB.toString() | 1 | 1 | 1 |
scheduler.SchedulerForB.updateMainDirection(Direction) | 3 | 1 | 3 |
scheduler.SchedulerForC.SchedulerForC(Elevator) | 1 | 1 | 1 |
scheduler.SchedulerForC.canGetOut(MarkRequest) | 2 | 2 | 3 |
scheduler.SchedulerForC.canPick(MarkRequest) | 10 | 10 | 18 |
scheduler.SchedulerForC.cntNeedDown() | 1 | 4 | 5 |
scheduler.SchedulerForC.cntNeedUp() | 1 | 4 | 5 |
scheduler.SchedulerForC.defaultMode() | 3 | 1 | 3 |
scheduler.SchedulerForC.dispatchRequest(PersonRequest) | 1 | 1 | 1 |
scheduler.SchedulerForC.getCarryNum() | 1 | 1 | 1 |
scheduler.SchedulerForC.getDirection() | 1 | 1 | 1 |
scheduler.SchedulerForC.getOrder() | 15 | 8 | 15 |
scheduler.SchedulerForC.getRequestsNum() | 1 | 1 | 1 |
scheduler.SchedulerForC.isFull() | 1 | 1 | 1 |
scheduler.SchedulerForC.isNeedServe() | 1 | 3 | 3 |
scheduler.SchedulerForC.needGetIn() | 3 | 2 | 3 |
scheduler.SchedulerForC.needGetOut() | 3 | 2 | 3 |
scheduler.SchedulerForC.passengersGetIn() | 1 | 5 | 5 |
scheduler.SchedulerForC.passengersGetOut() | 1 | 3 | 3 |
scheduler.SchedulerForC.toString() | 1 | 1 | 1 |
scheduler.SchedulerForC.updateMainDirection(Direction) | 3 | 1 | 3 |
tools.GlobalPermission.isSystemContinue() | 1 | 1 | 1 |
tools.GlobalPermission.systemQuit() | 1 | 1 | 1 |
tools.GlobalPermission.systemStart() | 1 | 1 | 1 |
tools.OutputHelper.OutputHelper() | 1 | 1 | 1 |
tools.OutputHelper.println(Object) | 1 | 1 | 1 |
tools.OutputHelper.println(boolean) | 1 | 1 | 1 |
tools.OutputHelper.println(char) | 1 | 1 | 1 |
tools.OutputHelper.println(char[]) | 1 | 1 | 1 |
tools.OutputHelper.println(double) | 1 | 1 | 1 |
tools.OutputHelper.println(float) | 1 | 1 | 1 |
tools.OutputHelper.println(int) | 1 | 1 | 1 |
tools.OutputHelper.println(long) | 1 | 1 | 1 |
tools.TimeManager.TimeManager(int,int,int) | 1 | 1 | 1 |
tools.TimeManager.idleSleep() | 1 | 2 | 2 |
tools.TimeManager.moveSleep() | 1 | 2 | 2 |
tools.TimeManager.serveSleep() | 1 | 2 | 2 |
Class | OCavg | WMC | |
ElevatorSystem | 4 | 4 | |
algorithm.AllocateStatus | n/a | 0 | |
algorithm.Allocater | 4.86 | 34 | |
algorithm.CanTakeMode | n/a | 0 | |
algorithm.RegionJudger | 1.29 | 22 | |
algorithm.RequestDivider | 7.25 | 29 | |
dispatcher.Dispatcher | 2.28 | 41 | |
elevator.Elevator | 2 | 32 | |
elevator.ElevatorOrder | n/a | 0 | |
elevator.ElevatorStatus | 1 | 8 | |
exception.FloorIdException | 1 | 1 | |
floor.Floor | 1 | 4 | |
floor.Rail | 1.78 | 16 | |
person.MoveOrderType | n/a | 0 | |
person.Person | 1 | 21 | |
person.PersonMoveOrder | 1 | 3 | |
person.PersonState | n/a | 0 | |
scheduler.MarkRequest | 1.64 | 18 | |
scheduler.SchedulerForA | 3.6 | 72 | |
scheduler.SchedulerForB | 3.35 | 67 | |
scheduler.SchedulerForC | 3.11 | 59 | |
scheduler.SchedulerType | n/a | 0 | |
tools.Direction | n/a | 0 | |
tools.GlobalPermission | 1 | 3 | |
tools.OutputHelper | 1 | 9 | |
tools.TimeManager | 1 | 4 | |
Package | v(G)avg | v(G)tot | |
6 | 6 | ||
algorithm | 4.18 | 117 | |
dispatcher | 2.39 | 43 | |
elevator | 1.67 | 40 | |
exception | 1 | 1 | |
floor | 1.92 | 25 | |
person | 1 | 24 | |
scheduler | 3.94 | 276 | |
tools | 1.19 | 19 | |
Module | v(G)avg | v(G)tot | |
Project7 | 2.83 | 551 | |
Project | v(G)avg | v(G)tot | |
project | 2.83 | 551 |
可見,本人此次的Scheduler
,Allocater
,RequestDivider
等幾個類的複雜度太高,此次的電梯設計較爲複雜,判斷邏輯較爲複雜,時間也比較緊,本人沒來得及解決這個問題,實屬遺憾。
單一責任原則
本次設計中,個人各個類的職責分工仍是比較明確的,好比RegionJudger
,RequestDivider
,Dispatcher
,Rail
,Scheduler
幾個類的協同工做,各司其職,井井有理,基本符合單一職責原則。
開放封閉原則
本次設計的開放封閉原則主要體如今Rail
上,這個類自己僅僅是給電梯一個樓層編號計算的支持,以及判斷是否具備停靠權限,且這是個不可變對象。這次設計中,這個判斷是否具備停靠權限的功能就在不作任何修改的狀況下直接應用於RegionJuder
的工做,體現了開放封閉原則。
里氏替換原則
本人這次設計又未使用繼承機制,故不涉及此處。
依賴倒置原則
本次做業本人採用了多種電梯的控制策略,都採用了Scheduler
這一接口,使其具備相同類型的業務功能。體現了依賴倒置原則
接口分離原則
此次的設計僅僅使用了Scheduler
這惟一的接口,且都是有必要的方法,故不涉及。
本次本人的優化主要使用的是wsb巨巨的優化策略,俗稱「電踢」策略,來實現半動態規劃。
RegionJuder
考慮不周
RegionJudger
的業務邏輯較爲複雜,稍有不慎就會出現考慮不周的狀況。本人在早期確實在此處有幾個Bug。不過這種Bug比較容易發現,評測機的大量數據下,這種Bug基本都能暴露出來。
Look
算法出現的Bug
當一個電梯處於IDLE
狀態,且此時上下同時各來一個請求且無其餘請求,那麼電梯將陷入永久保持IDLE的狀態,這個Bug是中測樣例查出來的。
B電梯在3樓開門
因爲本人給B電梯加入了根據自身負載決定是否在奇數樓層踢人下去分配給C電梯的功能且沒處理好3樓這個邊界條件,故在評測機的掃射下測出了一組B在3層開門的錯誤,加上一個特判後,問題就解決了。
以上問題所有在提交截止前解決,因此本人在強測與互測中未被查出Bug。
此次我好像又一次誤入了神仙屋,他們不只僅沒有被我查出Bug,性能還賊強,我太菜了,哭了。
輸出時間戳與本身設定輸入時間間的偏差影響評測
解決方案:
一、根據第一條輸出的時間與第一條輸入的時間進行偏差修正,同時放寬對時間的判斷的限度,加入0.05s的容許偏差。
二、使用hdl封裝的接口,聽說用這個能夠基本消除這個偏差,orz
管道被寫滿
以前的評測因爲輸出較短,通常不會出現這種狀況,因此本人沒有意識到這個問題,第七次做業中,本人給本身的代碼對拍時,發現會各類TLE,後來發現是管道寫滿了,寫入被阻塞,致使TLE
解決方案:
在不斷輪訓等待「輸入時間窗口」的時候判斷被測程序是否往管道中寫入了信息,若是寫入就讀出保存。
在Java能夠經過ImputStream
的available()
方法判斷管道內是否已經被寫入了信息(若是被寫入,那麼available != 0)。
使用Java對調用輸出流的println
一類的方法後,待測程序沒有接收到
解決方案:
隨手flush
是個好文明。
遇到死鎖的程序判處其TLE並防止它繼續耗費資源
解決方案:
不斷經過sleep輪訓process.isAlive()
與是否超過最大時限,若是超過最大時限(輪訓結束,且process.isAlive()
爲真)則判處TLE
,同時殺進程。
關於殺進程
ubuntu16.04
:直接process.destroy()
能夠把整個進程給殺乾淨。
win10
:僅僅經過process.destroy
沒法殺死整個進程,能夠經過taskkill
來殺死超時的進程。
關於CPU時間的測試
解決方案:
水羣裏一位同窗的方案,使用time命令
能夠查詢CPU時間,本人還沒有親自嘗試,下次窩窩做業能夠一試。
順便,time命令
好像win
沒有誒,哭哭。