OO_Unit2
一、架构设计迭代
1.hw5
1.1 类图
1.2 时序图
1.3 架构分析(变不变)
深入贯彻落实**”今朝有酒今朝醉”的原则,在博览博客之后,发现都说去年LOOK+自由竞争是活少分高**的不二选择✧(≖ ◡ ≖✿)
我果断加入LOOK大家庭,结(zhao)合(chao)实验代码,草率搓出了第一版
Main
运行InputThread
输入线程、Schedule
调度器(我其实之前耦合在输入线程里面)、Elevator
电梯线程共享的数据类型只有
Pesron
记录人员请求信息、RequestTable
管理人员请求信息策略类
Strategy
,采用LOOK算法
梦幻开局,我还天真的认为:电梯月?就这??(๑>ڡ<)☆
1.4 调度器设计
1 |
|
在这次作业没什么存在性的东西,直接按照输入分配
1.5 同步块与锁
对RequestTable
里的所有方法统统上锁一劳永逸✧ (≖ ‿ ≖)✧
在Strategy
类里遍历RequestTable
里容器的时候别忘上锁,不然有几率触发Java.util.ConcurrentModificationException
1 | public boolean reqSameDirection(int eleFloor, boolean eleDirection) { |
2.hw6
2.1 类图
2.2 时序图
2.3 架构分析(变不变)
适逢清明假期,周一得知不能使用自由竞争的我缓缓裂开 º·(˚ ˃̣̣̥᷄⌓˂̣̣̥᷅ )‧º·˚
抛开调度策略不谈(随机是我最后的港湾),重构启动!!!
本次作业新增RESET
,将重构总结为四步
输入线程得到reset请求->mainRequest新增resetRequest请求队列数据结构
调度线程分配reset请求->eleRequest新增resetRequest数据结构
电梯类加入reset执行过程->放人->输出begin->返回请求->改电梯属性->输出end
策略类新增
RESET
建议
1 | if (request.getResetRequest() != null) { |
2.4 调度器设计
心比天高不自量力,遂开始研究影子电梯,苦于前人记载较模糊,只有“用计时代替sleep”,完全不会做(╯#-_-)╯╧═╧
不想写深克隆也不想考虑是不是线程安全(我至今觉得下面的代码有问题就是没被hack到hhh)
写了一个丑陋的shadow
类,来负责计算
1 | public Shadow(Elevator elevator) { |
参考前人博客遍历6个电梯,找出能够使得新请求加入后整体运行时间结束最早的进行分配
丑陋抽象的实现了“影子电梯”,为第三次无法完全模拟电梯行为埋下祸根( >﹏<。)~
2.5 同步块与锁
1 | ResetRequest resetRequest = mainRequestTable.getOneReset(); |
新增对应调度器内的resetElevator
、dispatch
方法分别上锁,确保不会同时执行
2.6 结束条件
1 | if (mainRequestTable.isPersonEmpty() && mainRequestTable.isResetEmpty() |
mainRequestTable
所有请求处理完毕(reset & person)输入结束
每部电梯所有请求处理完毕(reset & person)
3.hw7
3.1 类图
3.2 时序图
3.3 架构分析(变不变)
本周新增DCElevator
,对此我强烈建议成立影子电梯受害者联盟 º·(˚ ˃̣̣̥᷄⌓˂̣̣̥᷅ )‧º·˚
秉持着菜就多练的原则,本周我灵活运用达芬奇睡眠法,倾情加入Buffer神教,继续深耕影子电梯
butttttttttt 缝缝补补到周六早八,还是有bug………
一怒之下,转身向随机算法+随机地大小睡走去
if u wanna sleep ,u must sleep ,著名哲学家,在周六九点终于入睡的汀小姐如是说道
3.4 调度器设计
本来我通过罚时粗糙模拟了Gemini电梯的运行时间,但遇到了如下问题
1 | //debug实录 |
今天交了一波强测,发现全AC了,世界是一个巨大的笑话 ——4.19
于是转身向随机走去
1 | public synchronized int randomDispatch(Person person) { |
3.5 Gemini电梯防碰撞
仿照RESET
指令,很容易复现DCRESET
,区别在于DCRESET
在1.2s执行结束后我选择终止电梯线程
原电梯线程在调度器里新建Gemini
类(双子星!姐妹儿英语真有水平),管理新建AB两个电梯
继续沿用LOOK策略,因为我只要确保人员分配正确、运行特判就可以让它们在现有架构下正确工作,我们要做的是对Gemini电梯的移动特殊规范一下(电梯防撞)
最关键的电梯防撞:
我起初想不要让电梯占用TransferFloor,来了干完活就走,但人总是喜欢自己为难自己(๑>ڡ<)☆
探索之后,我写出了这样的shit
1 | public void moveSpecial() { |
设置一个
floor
类来表示换乘层是否占用,内存AB两电梯的请求表如果A想进入换乘层,
floor
被占用,就向请求表发送离开换乘层的请求,Asleep
一下另一部电梯(B)离开后,
floor.awayTransfer()
设置换乘层不被占用标志此时A睡醒了进入换乘层进行放人操作
如果A主动离开换乘层(有人需要接),
floor.awayTransfer()
设置换乘层不被占用标志
一睡到底逃避锁的竞争,不愧是我T_T
直到今天复习OS的时候看到进程互斥的软件实现,我有种似曾相识的感觉……这错误集锦是在骂我!!!
3.6 结束条件
和上次相比新增changeMan == 0
分配去换乘的乘客要坐上最后一班列车,我们才能放心和OO第二单元告别啊º·(˚ ˃̣̣̥᷄⌓˂̣̣̥᷅ )‧º·˚ ~
1 | public static synchronized void decreaceChangeMan() { |
二、bug分析
1.hw5
de出来的bug
可恶的Java.util.ConcurrentModificationException
线程不安全de遍历RequestTable
里容器的时候一遍删除一遍遍历,别忘记上锁
第一次作业差点寄在这里了
1 | public boolean reqSameDirection(int eleFloor, boolean eleDirection) { |
强测和互测
均没有hack和被hack 我们都好优秀(*>◡❛)
2.hw6
de出来的bug
- 电梯最大人数忘记改居然还能过中测????
- RESET_BEGIN在人员请求返回主表之后才输出
强测和互测
强测多亏了伟大的影子电梯
互测进入了围城必阙副本
一时齐发众妙毕备!!!!因为设置RESET
电梯不接客所以大量请求就会涌入唯一一部不在RESET
的电梯T_T
1 | [1.0]RESET-Elevator-6-3-0.6 |
这种数据我一刀连上自己能刀7个人º·(˚ ˃̣̣̥᷄⌓˂̣̣̥᷅ )‧º·˚ (PS:我是文明人,这刀我就使一次)
此外还发现了一些同学reset调度上的一些bug
真是一次快乐刀人的体验 成功率高达33.3%╰ ( ´⌣` )╯
3.hw7
de出来的bug
AB电梯结束在停靠层,要在OVER
之前先请它离开停靠层
1 | if (request.isEnd()) { |
de不出来的bug
- 影子电梯内请求表即使深克隆也会莫名其妙被篡改
- buffer内的人减数分裂了
- 影子电梯初始化时原电梯加锁后还会被篡改
强测和互测
伟大的随机没有bug(๑ơ ₃ ơ)♥
房间里有最后一条RESET就爆炸的地雷
还有同学电梯防撞做的不到位
(要我说就该随地大小睡)还有同学调度器写的有问题,有请求处理不完就覆盖了,但抽不到这张bug卡T_T
4.debug方法
- 首先写之前确保自己的运行逻辑没有漏洞
- 其次使用大量数据来抽卡找bug
- 使用printf大法复现bug,python里多开线程测这个错误数据来提高爆率
- 对于轮询bug,在while(true)里面使用printf大法定位,通过sleep来避免
勇敢放弃de不出来的bug,选择有简洁美的随机
三、心得体会
1.线程安全
起初对线程安全只有一个模糊的概念,不就是对RequestTable
上锁?后期迭代老师建议将电梯与电梯线程分离,但因为偷懒我一意孤行将电梯保持共商共建共享开放包容。因此我遇到了数不清的线程安全问题T_T
关于读写锁,我也只是在理论课和实验课代码中浅尝辄止,因为偷懒我一意孤行只使用synchronized
,性能差差的很安心T_T
我想如果这单元能重来一遍,我一定会好好重构一次线程安全的优雅的代码,可惜没如果º·(˚ ˃̣̣̥᷄⌓˂̣̣̥᷅ )‧º·˚ ~
2.层次化设计
这单元的层次化设计非常清晰!基本架构沿用了三次作业
输入线程、调度线程、电梯线程三板斧
请求表、人员为共享资源
电梯运行与策略分离
良好的层次化设计让我每次新增代码量不多(思考量不少
四、心情体会
生活不止代码,高分值得我加倍付出努力,但它绝不是我生活的主旋律 (^∇^☆)
美好的清明假期,无法割舍的是
没有打成的明日方舟桌游,无法割舍的是凌晨的麦麦,无法割舍的是与同学海底捞小聚,无法割舍的是人大旁边的萨莉亚,无法割舍的是五道口的棋牌室,无法割舍的是朋友和稍纵即逝的青春(谁家6系人天天吃喝玩乐啊喂)看到这里的大家都注意身体健康!
连续两周一坐坐一天对着密密麻麻数据debug,我能精准的记忆每位乘客不同调度策略的概率和我的bug出现概率
夜昏乍似灯将灭,朝暗长疑镜未磨……我该换新眼镜(眼睛)了(ฅ´ω`ฅ)
自我为难和放过自我之间的平衡
对于不打算深耕cs专业的我,着了什么魔非要写影子电梯呢??可能是被追求卓越的大家感染了吧hhhh
但我最后因为心得第一点和菜的原因,还是选择放过自我,随机真香啊suki!!!(ฅ´ω`ฅ)
结尾致谢
感谢亲亲舍友帮我找出来无数的bug
cozy!“你一句你别急真不晚,我就到了真江南”
Shae!267yyds!!存在即安心
luma!睡神!noSleep_noSleep感谢耐心帮助、精神鼓励的良师益友们
感谢讨论区以及开发测评机的无私奉献的佬们
感谢OO课程组的倾情付出 给了我神奇的电梯月体验º·(˚ ˃̣̣̥᷄⌓˂̣̣̥᷅ )‧º·˚ ~