标签:hack 异常 找不到 写博客 rri 转变 多个 专注 handle
通过Unit2的学习,我了解到Java多线程的相关知识,认识到单例模式、生产者-消费者模式、观察者模式、工人模式等设计模式,并通过设计基于SSTF算法的电梯加深对多线程知识的理解,同时将一部分设计模式加以应用。本博文从设计策略概述、架构可扩展性分析、程序结构分析、Bug分析(含自身Bug分析与他人Bug分析)及心得体会五方面展开,总结在Unit2中的收获。
类
设计模式
使用生产者-消费者模式,输入处理类充当”生产者“,管理者类充当”托盘“,电梯类充当”消费者“,请求充当”产品“。
使用单例模式
构造单例的传统方法——饿汉法
private static Manager instance = new Manager();
private Manager() {
}
;
public static Manager getInstance() {
return instance;
}
本次作业中使用的构造单例的方法——双重锁法
private static volatile Manager instance;
private Manager() {
}
;
public static Manager getInstance() {
if (instance == null) {
synchronized (Manager.class) {
if (instance == null) {
instance = new Manager();
}
}
}
return instance;
}
两种单例构造方法的评价
基本思路
关键类说明
调度策略:以主请求mainRequest为电梯的控制主线,电梯的工作始终围绕一个目标——完成当前主请求。在电梯完成一主请求后,若管理者暂不可为其分配新的主请求,则电梯陷入wait状态。当管理者接收到输入端传来的请求时,将请求加入外部请求队列,并notifyAll,唤醒处于wait状态的电梯向管理者申请新的主请求。
捎带策略:当且仅当当前楼层存在目标方向与电梯运行方向相同的外部请求时,管理者让电梯进行捎带。每次捎带让当前楼层的所有外部请求均成为电梯内部请求。
优化策略:采用一种紧扣局部优解的贪心算法——SSTF算法分配主请求,并辅以时间预测提升性能,具体说明如下:
SSTF算法流程示意图:
时间预测的例子:当前电梯要将主请求从10层运至1层,当电梯从5层到达4层时,判断6层、7层(即时间预测的范围为two floors)是否有向下的请求。若有,在电梯本应播报“到达4层”并将当前层号置为4时,让电梯”反抗“主请求的操纵,并以”光速“到达6层(即改为播报”到达6层“并将当前层号置为6)。PS:时间预测仅改变电梯一时的运行方向,电梯的主要运行方向仍由主请求操纵。此方法融合了一定的LOOK算法回头的思想,虽“量子电梯”有悖现实,但经过大量随机数据测试,可以有效提升SSTF算法在作业性能上的缺陷。
结束策略:当输入处理器读入的请求为null时,将管理者的结束控制符toEnd由false置为true,并唤醒处于wait状态的电梯。此时被唤醒的电梯继续寻找新的主请求,若寻找不到,直接结束线程;否则,处理找到的新的主请求,直到寻找不到主请求为止。
线程协同策略:本次作业中,将输入处理类与电梯类(即生产者与消费者类)作为线程,管理者仅作为生产者与消费者进行数据交互的非线程类。输入处理类与电梯类的共享变量仅有两个,一是外部请求队列outRequests,另一是结束控制符toEnd。考虑到管理者类中关于这两个变量的方法均不长,再加上完成本次作业时对object锁的理解还不太深入,故采用对这些方法进行synchronized加锁的方式确保线程安全。
新增类
设计模式
基本思路
关键类说明
调度策略:仍沿用第一次作业中的思路,将mainRequest作为电梯控制的主线。所不同的是,在引入多部电梯后,管理者类需要为每个新加入的外部请求,安排合适的闲置电梯。闲置电梯的安排仍然采用贪心的思想,即为外部请求安排最近的闲置电梯。
捎带策略:电梯到达每一层时,先让到达目的地的所有乘客出电梯,后执行类似于下述的伪代码:
if (主请求在当前层进入) {
要捎带;
if (电梯内满人) {
用贪心思想选取电梯内一人暂时离开电梯,并投出新的外部请求;
}
主请求先进入电梯;
让外部请求按一定优先顺序进入电梯,直到电梯内满人;
} else {
if (电梯内满人) {
不捎带;
} else {
if (有同向请求) {
让外部请求按一定优先顺序进入电梯,最多到电梯内满人;
} else {
不捎带;
}
}
}
return;
优化策略:保留第一次作业中的SSTF算法和时间预测。
结束策略:与第一次作业相类似,略有不同的地方在于toEnd置为true后,管理者类要将所有的处于wait状态的电梯逐一唤醒。
线程协同策略:本次作业中,仍然要关注toEnd与outRequests这两个生产者、消费者所共享的变量。与第一次作业不同的是,为了更灵活地使用锁,更方便地完整特定线程的唤醒,并更好地监控锁的重入深度以方便调试,我将所有的synchronized方法锁全部用ReentrantLock锁对象lock进行处理。
特定线程唤醒的方法:在管理者类中设一conditions队列,与elevators队列中的每一个电梯相对应,充当每一个电梯的“唤醒师”。
要让特定电梯睡眠时,采用语句:
conditions.get(elevator.getEleId() - ‘A‘).await();
要唤醒特定电梯时,采用语句:
conditions.get(elevator.getEleId() - ‘A‘).signal();
监控锁的重入深度的方法:使用ReentrantLock对象的getHoldCount方法。
新增类
设计模式
基本思路
关键类说明
调度策略:仍沿用第二次作业中的思路,所不同的是电梯与外部请求的距离衡量公式发生变化,变为Math.abs(楼层差) * 电梯移动一层的时间。
捎带策略:电梯到达每一层时,先让到达目的地的所有乘客出电梯,后执行类似于下述的伪代码:
if (主请求在当前层) {
要捎带;
if (电梯内满人) {
用贪心思想选取电梯内一人暂时离开电梯,并投出新的外部请求;
}
主请求先进入电梯;
让可完成的外部请求按一定优先顺序进入电梯,直到电梯内满人;
} else {
if (电梯内满人) {
不捎带;
} else {
if (有可完成的同向请求) {
if (电梯类型非A) {
让可完成的外部请求按一定优先顺序进入电梯,最多到电梯内满人;
} else {
让可完成的同向外部请求按一定优先顺序进入电梯,最多到电梯内满人;
}
} else {
不捎带;
}
}
}
return;
优化策略:保留前两次作业中的SSTF算法和时间预测,并进行如下调整:
结束策略:
if (输入处理器读入请求null || 一架电梯在某一层完成一次进出) {
输入处理器将管理者的结束控制符toEnd由false置为true;
唤醒所有处于wait状态的电梯;
被唤醒的电梯继续寻找新的主请求;
if (寻找不到新的主请求) {
if (Condition1:所有电梯的内部请求nextRequest && Condition2:外部请求队列为空) {
直接结束电梯线程;
} else {
电梯陷入wait状态;
}
} else {
处理找到的新的主请求,直到寻找不到主请求且满足Condition1与Condition2为止;
}
}
线程协同策略:本次作业沿用第二次作业中的lock线程同步机制以及condition唤醒特定线程的方法,所不同的是取消管理者的conditions队列,而在每个电梯中增加一Condition对象作为属性,相当于将电梯的“唤醒师”封装至电梯中。
一种优化策略:基于“流水线”的思想,设一合适的时间阈值,一个包含换乘后请求的请求加入外部请求队列时,估计MAX(换成前请求的执行时间,MIN(闲置电梯到达换乘后请求出发楼层的时间)),若该值小于所设定的阈值,则表明适合提前安排换乘后请求为一闲置电梯的新的主请求。若所安排的电梯到达换乘后请求的出发楼层后,换乘前请求还未完成,则wait等待。多次随机模拟表明,这种做法能在一定程度上提升性能(当然阈值要设好),但由于本人在设计中出现了死锁,最终难以复现,又没有时间Debug了,最后只好铩羽而归。
评测中的灵异事件:本人在强测中,一个点99.8+,部分点99.99+,部分点100,唯独一个点出现了令人瞩目的80(qaq qaq qaq)。在本机跑过多次后,时间均为85s,而评测时显示的时间为95s。通过分析强测的stdout,我发现了如下的奇异输出:
[77.3810]ARRIVE-6-B
[77.3820]OPEN-6-B
[81.0910]IN-286-6-B
…… ……
[82.9920]ARRIVE-9-B
[82.9940]CLOSE-8-X1
[85.3750]ARRIVE-10-B
(99.8+的那个点也有出现中间停了4s的情况)
经过与wsb大佬的讨论,这是由于强测的评测环境高度并发,设有各种各样的系统时间切片所致的。不过课程组明确表示,所有请求的投放时间都是一致的,会保证评测的公平性。
度量结果
类图
协作图
评价
度量结果
类图
协作图
评价
度量结果
类图
协作图
评价
在互测、强测中,均未出现本人自身的bug;中测第一次提交遍地红WA,原因是把人从电梯中出去的信息播报打成“sb-OUT-x”了。
本次作业在私下测试的过程中,可以说是相当顺利的,除了一些极其容易测出来的“打错型”Bug外,并未发现任何Bug。尤其是在线程协同方面,可以说是没能吃到苦头。
在互测中,用同一样例成功hack到两名同学
stdin:
[5.4]1-FROM-1-TO-7
[9.4]2-FROM-7-TO-10
[9.4]3-FROM-7-TO-6
在互测、中测、强测中,均未出现本人自身的bug。
本次作业在课下开启自动评测机后,发现了多处Bug,其中大部分是“打错型”Bug,在此只能说一个自创词——熬夜伤目。有一个Bug让我印象颇深,至今还没有弄清楚其中的原因,我在此作下介绍:
我原来采用的条件唤醒方法是,不设Condition对象,而采用synchronized(电梯对象)的方式,让电梯陷入wait和被唤醒均在此synchronized区块中。按理来说各电梯对象不尽相同,wait对应的monitor自然不尽相同,这和为各电梯对象分配不尽相同的Condition对象是类似的。但实测中极少部分样例出现类似死锁的现象。经过println大法以及getHoldCount方法发现,两架并不处于wait状态的电梯在执行电梯类内部代码时,要进入管理者类中执行两个不同的lock(管理者类的属性锁)区域内的代码,此时lock的holdCount为0,按理来说会有一架电梯先获得管理者类的属性锁,获得管理者单例这个监控器,执行相应区块代码,然而两架电梯均发生了阻塞现象。但此时的holdCount明明为0,而且换成类似的Condition大法后就没有这样的问题的了,所以个人表示一脸懵逼......
若有同学遇到过类似的Bug,即对象锁特定唤醒不管用,而一一对应的Condition特定唤醒管用的情况,或是对此Bug的原因有个人见解,欢迎添加VX号taikan199私聊我!!!
在互测中,成功hack到一名同学
stdin:
[0.0]3
[2.3]1-FROM-7-TO--2
[2.3]2-FROM-7-TO-9
[2.3]3-FROM-7-TO-10
[2.3]4-FROM-7-TO-3
[2.3]5-FROM-7-TO-6
[2.3]6-FROM-7-TO--1
[2.3]7-FROM-7-TO-4
[2.3]8-FROM-7-TO-2
[2.3]9-FROM-7-TO-1
[2.3]10-FROM-7-TO--3
[2.3]11-FROM-7-TO-5
[3.5]12-FROM-7-TO-8
[3.5]13-FROM-9-TO--3
[3.5]14-FROM-9-TO-10
[3.5]15-FROM-9-TO-3
[3.5]16-FROM-9-TO-7
[3.5]17-FROM-9-TO--1
[3.5]18-FROM-9-TO-1
[3.5]19-FROM-9-TO-5
[3.5]20-FROM-9-TO-8
[3.5]21-FROM-9-TO-4
[3.5]22-FROM-9-TO-6
[4.7]23-FROM-9-TO--2
[4.7]24-FROM-9-TO-2
[4.7]25-FROM-7-TO-1
[4.7]26-FROM-7-TO-8
[4.7]27-FROM-7-TO-4
[4.7]28-FROM-7-TO-2
[4.7]29-FROM-7-TO--2
[4.7]30-FROM-7-TO-3
[4.7]31-FROM-7-TO--3
[4.7]32-FROM-7-TO-5
[4.7]33-FROM-7-TO-10
[5.9]34-FROM-7-TO-9
[5.9]35-FROM-7-TO--1
[5.9]36-FROM-7-TO-6
[5.9]37-FROM-10-TO--1
[5.9]38-FROM-10-TO--3
[5.9]39-FROM-10-TO-4
[5.9]40-FROM-10-TO-5
[5.9]41-FROM-10-TO-7
[5.9]42-FROM-10-TO-2
[5.9]43-FROM-10-TO-8
[5.9]44-FROM-10-TO-9
在互测、中测、强测中,均未出现本人自身的bug。
本次作业在课下共发现两个主要Bug,下面展开介绍
在互测中,成功hack到一名同学
stdin:
[1.0]X1-ADD-ELEVATOR-C
[1.0]182-FROM--1-TO-7
[1.0]X2-ADD-ELEVATOR-B
本单元的3次hack,均采用手动测边界、自动测功能的方法,这与在中测阶段测试自身程序的方法相同。
本单元的4个成功hack,均由本人独享,其中第一次作业和第二次作业的成功hack结果还是在最后一次cd之后才出现的,颇为惊险刺激。事实上,第二次与第三次作业中,本人的room中各有一位同学出现死锁,但触发频率极低,所以最后都没hack成。(尤其第三次作业,room中多位同学疯狂开火炮,结果全部naive)
同第一单元的测试相比,本单元测试有以下差异:
标签:hack 异常 找不到 写博客 rri 转变 多个 专注 handle
原文地址:https://www.cnblogs.com/palemodel/p/12717190.html