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
没有诶,哭哭。