标签:没有 notify 失败 参数 final tip 接口编程 -o cer
? 本题完成的任务为多部多线程可捎带调度电梯的模拟,电梯系统具有的功能为:上下行、开关门、新增一部可以使用的电梯,电梯系统在某一层开关门时间内可以上下乘客。电梯系统可以采用任一的调度策略,只要保证在一定时间内将所有乘客送至目的地即可。
? 本题采用的是目的选层电梯,在电梯的每层入口,都有一个输入装置,让每个乘客输入自己的目的楼层,所以一个电梯请求除了人员id,还有这个人的出发楼层和目的楼层。
? 电梯类型分为A型
、B型
、C型
,在新增电梯时指定类型。初始有3部电梯,编号分别为A
、B
、C
,新增电梯编号为X1
、X2
、……、Xn
。三类电梯的开关门时间都分别为0.2s
。
-3, -2, -1, 1, 15~20
0.4s
6人
-2, -1, 1, 2, 4~15
0.5s
7人
1, 3, 5, 7, 9, 11, 13, 15
0.6s
8人
[1.0]X1-ADD-ELEVATOR-A
[2.0]1-FROM--3-TO-2
[2.4060]ARRIVE--1-X1
[2.8070]ARRIVE--2-X1
[3.2070]ARRIVE--3-X1
[3.2080]OPEN--3-X1
[3.2080]IN-1--3-X1
[3.6080]CLOSE--3-X1
[4.0090]ARRIVE--2-X1
[4.4100]ARRIVE--1-X1
[4.8100]ARRIVE-1-X1
[4.8100]OPEN-1-X1
[4.8100]OPEN-1-B
[4.8110]OUT-1-1-X1
[4.8110]IN-1-1-B
[5.2120]CLOSE-1-B
[5.2120]CLOSE-1-X1
[5.7120]ARRIVE-2-B
[5.7120]OPEN-2-B
[5.7130]OUT-1-2-B
[6.1130]CLOSE-2-B
ALS电梯的请求分为主请求和被捎带请求
主请求选择规则:
被捎带请求选择规则:
电梯的主请求存在,即主请求到该请求进入电梯时尚未完成
该请求到达请求队列的时间小于等于电梯到达该请求出发楼层关门的截止时间
电梯的运行方向和该请求的目标方向一致。即电梯主请求的目标楼层和被捎带请求的目标楼
层,两者在当前楼层的同一侧。
其他:
? SCAN调度策略,使电梯沿一个方向进行扫描,每到达一个楼层,捎带当前楼层本电梯可以捎带(该请求的到达楼层是本电梯可停靠的楼层且电梯此时尚未满载)的请求,直至电梯到达运动方向上最远的可停靠层,再转变运动方向进行扫描。简单来说,理解为电梯在最低和最高可停靠层来回扫描,同时捎带和完成请求。
? 很明显,这样的调度策略很有可能会造成性能的损失,如果运动方向上没有需要捎带的请求或者电梯已无法捎带请求并且目前已在电梯内的请求需要停靠的楼层都在相反方向,则可以立刻调转方向扫描,减少来回的无效路程,这就是LOOK调度策略,具体的电梯线程实现可见下方的流程图。(有人可能会说,万一调转方向后,原先的运动方向上产生了需要捎带的请求呢?本人的观点是,这种情况的确有可能出现,但是电梯无法预知未来,所以只能选择当前情况下的最优选择,在大部分情况中,采用LOOK调度的性能要比SCAN调度好)
? 由于本次题目的请求并不一定可以由一个电梯单独完成,所以需要让乘客进行换乘。
? 具体的实现方式是:在PersonRequest
类的原有属性fromFloor
和toFloor
上增加finalFloor
属性,如果该请求不需要换乘,将finalFloor
赋值为0,否则将finalFloor
赋值为toFloor
,将toFloor
赋值为中转楼层。当该请求到达中转楼层toFloor
时,向调度器的请求队列中增加一个新请求,新请求的fromFloor
为中转楼层、toFloor
为原先的finalFloor
(即该请求所要到达的最终楼层)、finalFloor
为0。具体的换乘策略如下表所示:
fromFloor | toFloor | 中转楼层 |
---|---|---|
-3 | 2~14 | 1 |
-2、-1、2 | 3 | 1 |
2~14 | -3 | 1 |
3 | -2、-1、2 | 1 |
3 | 4、6、8、10、12、14 | 5 |
4、6~14 | 3 | 5 |
16~20 | 2~14 | 15 |
2~14 | 16~20 | 15 |
? 生产者(Producer)是负责产生数据的线程,消费者(Consumer)是处理数据的线程,当生产者消费者以不同的线程运行时,两者之间的速度差异会引起问题,比如消费者想要获取数据,数据还未生成;生产者想要交付数据,消费者还无法接收数据。为了解决这种生产者和消费者的强耦合问题,可以让生产者消费者通过缓冲区(Channel)进行通讯,进而消除不同线程间处理速度的差异。
? 通俗来说,生产者将生产的数据直接移交缓冲区,消费者直接从缓冲区中提取需要的数据,两者不直接交互。
? 观察者模式定义了对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新,最典型的例子就是微信公众号订阅与通知系统。
? 微信公众号是被观察者,每一个关注公众号的用户是观察者。一旦公众号有更新(被观察者状态改变),就会向每一个关注该公众号的用户推送信息(通知观察者),然后关注此公众号的用户在微信中看到新信息(观察者状态更新)。
update
方法,用于被观察者状态更新后对观察者进行通知。update
方法实现通知与观察者的更新。wait()
使消费者线程进入等待状态,等待notifyAll()
指令唤醒线程。其实,多线程协调运行的原则就是,当条件不满足时,线程进入等待状态;当条件满足时,线程被唤醒,继续执行任务。synchronized
的方法中都notifyAll()
public synchronized void method() { // 锁住this
? ……
} // 释放锁
? 用synchronized
修饰的方法是同步方法,锁住的对象是this
,也就是调用该方法的实例,在生产者-消费者
模式中,锁住的通常就是共享对象。
wait()
)释放锁时,位于object锁池中的线程去竞争这把锁,竞争成功的线程则获得这把锁,竞争失败的线程则继续被阻塞在锁池中。wait()
时,线程A会释放object的锁同时A就进入object的等待池等待,当锁被释放时,等待池中的线程不会去竞争该对象的锁。当object的notifyAll()
被调用后,会唤醒所有等待池中的线程,被唤醒的线程进入object的锁池中,这些线程就可以去竞争object的锁了。? 在对锁池和等待池有一个清晰的了解下,可知绝大多数情况下,可以理解为该同步方法可能改变其他等待池中线程的状态(使其不再等待)时,才需要在保证线程安全的地方加上notifyAll()
唤醒等待池中的线程。
以下内容引自课件“面向对象程序的需求分析与设计原则-1-分析与设计原则”
? SRP原则,顾名思义,就是每个类或方法都只有一个明确的职责,类职责就是使用多个方法从多个方面来综合维护对象所管理的数据,方法职责就是从某个特定方面来维护对象的状态(更新、查询等)。
? 如果类或方法的职责过多,会导致类或方法的逻辑难以封闭,容易受到外部的影响,因外部因素的变化而变化。
? OCP原则的含义是对扩展开放,对修改关闭。简单来说,当程序进行扩展增加新功能(open)时,不需要修改原有的代码(close)。OCP原则能够使程序的扩展性更好,易于维护和升级。
? 在使用继承实现OCP原则的过程中,需要保持好子类和父类之间的交互关系,并使用好接口和抽象类。
? LSP原则的含义是任何父类出现的地方都可以用子类来代替,并且不会导致相应类的程序出现错误。实现OCP原则的关键步骤就是抽象化,而父类与子类的继承关系就是抽象化的具体实现,所以LSP原则是对实现抽象化的具体步骤的规范。
? ISP原则的含义是一个接口只封装一组高度内聚的操作,使用多个隔离的接口,避免封装多种可选的方案,降低类之间的耦合度。
? DIP原则的含义是高层次模块不应该依赖于低层次模块,应该依赖于抽象,针对接口编程。
标签:没有 notify 失败 参数 final tip 接口编程 -o cer
原文地址:https://www.cnblogs.com/nickhan-cs/p/12710926.html