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也就不足为奇了。
多线程设计让我明白了如下几点:
但愿在之后的学习中,我能够更好地掌握测试方法,写出更加完美的程序。