BUAA_OO_2024 Unit 2 BLOG

邝晓文-22373445 学生 2024-04-20 18:18:10

BUAA_OO_2024 Unit 2 BLOG

任务简介:模拟多线程实时电梯系统,通过设计,系统可以调度多部电梯完成乘客请求或重置操作。

锁与同步块

采用了不需自己实现的synchronized这种锁,它可以:

  • 修饰方法
  • 修饰代码块

在实现中仅用了前一种使用方式,即“对方法加锁”,对于设置的共享对象,即候乘表类中的每一个方法都用synchronized关键字修饰,确保其被多个线程修改和访问时不会出现问题。所以,锁的对象应该是同步块代码语句中修改需要保护的对象。synchronized可以修饰静态方法,也可以修饰实例方法,但二者锁的对象却存在差别,注意需要正确选择。

调度器设计

调度器需要对Request进行处理,以便请求能够被正确满足,将其单独作为一个线程。
该线程需要与输入线程、电梯线程进行交互,它们之间其实是生产者-消费者这一协作关系,与输入线程这一生产者之间的“托盘”是总候乘表,而与电梯线程这一消费者之间的“托盘”则是每个电梯各有的子候乘表。特别地,由于电梯重置时会将未完成请求重新返还给调度器进行再分配,所以电梯也是生产者,它们之间的“托盘”也是总候乘表。

调度策略需要综合考虑到各方面的因素,从乘客的角度来说,我们不希望完成请求的时间过长,而从电梯的角度考虑,我们希望能多多捎带,减少非必要移动和开关门,降低耗电量。
在hw6中,由于需要自己分配完成请求的电梯,我采用了下述调度策略:

<1>
优先分配给LOOK算法下能捎带的电梯。
注意“能捎带”是指不会导致原有请求无法完成,即不会出现原定捎带由于满员而无法满足的问题。

<2>
无可捎带电梯,分配空电梯。
这主要是考虑到时间问题,通过分配空闲电梯,可以使得请求及时得到满足。

<3>
无满足上述两种情况电梯,则分配给现有请求数最少的电梯。
当然也可能出现请求数相等情况等,此时可以从是否在重置、是否为双轿厢(耗电少)、电梯所处楼层与目标楼层的距离等方面考虑最终分配给哪个电梯。

LOOK算法

  • 规定电梯初始方向,电梯朝该方向移动
  • 到达新楼层,判断是否需要开门(电梯策略类给出建议),开门的条件有:
    • 有乘客到达目的地
    • 该楼层有可捎带(同向)请求,要让新乘客进入
  • 判断电梯状态,若电梯中仍有乘客,继续移动,否则检查请求队列
    • 请求队列不为空
      • 存在请求在电梯“前方”,继续移动
      • 电梯“前方”没有请求,电梯转向(不是朝反方向移动,因为同层可能有反向请求),继续循环判断即可
    • 请求队列为空
      • 不再有新请求,电梯线程结束
      • 仍可能有新请求加入,电梯在该楼层wait即可

LOOK算法优势
课程组采用ALS调度策略为性能基准,但是通过查阅资料和研讨课讨论,最终选择了LOOK作为调度算法

  • 在ALS调度策略中,低、高层请求可能由于难以捎带而被堆积,直至有相关请求符合主请求规则时,才运行到低层或高层进行集中处理,效率不佳。
  • LOOK算法更加贴近真实电梯的策略,维护当前的运行方向,在“前方”更远层无请求时才转向。

架构分析

UML类图

hw5

img

现在回看第一次作业的设计,可以说有很多不合理和不成熟的地方,但是也是建立起了整个请求处理的架构,形成了输入线程和电梯线程间的协作关系。主要的缺陷有:

  • Request的功能其实通过课程组所给的接口都可以实现,过于冗余
  • RequestTable既是总候乘表也是子候乘表,但在个人实现中二者存在挺多差别,都用RequestTable来实现有很多不方便的地方
  • Elevator既需要存储电梯信息,也需要完成电梯行为(wait、move),在电梯线程中存储大量信息是否是合理的仍需要进一步考量

hw5->hw6/7

img

  • 在后面两次作业中,就修改了上述提到的不足之处,并且为了完成双轿厢电梯等任务,新建了DoubleElevator等。
  • 可以说在第一次作业中,对多线程的认识不够深入,线程间的交互关系有模糊混乱之处,在迭代时都有意去修改,使得各部分都能够被更合理使用,并且有更好的扩展能力,而不需要大幅改动原有框架。
  • 但是仍有不足,例如普通电梯和双轿厢电梯最好是以继承基础电梯的方式实现,至于如何实现run()方法,则可以通过实现Runnable接口的方式,以及通过子调度器来调度双轿厢电梯我总觉得有不妥之处,或许有更好的形式来实现。

协作图

img

上图中展现了不同线程之间的协作关系,其中InputThread、Scheduler、Elevator三者之间的协作还需要通过总候乘表waitTable来实现,Scheduler和Elevator之间的协作也需要通过子候乘表RequestTable来完成,确保线程协作的正确性。

稳定/易变的内容

  • 稳定的内容:在迭代过程中,电梯的调度策略(LOOK策略)在第一次作业中确定后则一直沿用,可以说是十分稳定。毕竟无论电梯的形式再怎么变化,最终都是要“把分配给其的请求完成”,所以从纵向调度的角度来说,这会是比较稳定的部分,不需要做过多的修改。
  • 易变的内容:其一是电梯的限制条件,在第二、三次作业中都增加了电梯重置这一操作,且要求响应时间不宜过长,电梯在重置后,其运行速度、承载人数、移动空间范围都可能会发生变化,所以在设计的时候应该确保这些都是可以灵活修改的;其二是电梯的分配策略,可以说不同的分配策略都各有优劣,但也很难保证某种策略总能在各个维度达到最优,且在各次作业中,实现每种分配策略的难度也有所差别,所以在将请求分配给电梯时所采用的策略是有很大的自我发挥空间。

双轿厢设计

在hw7中,电梯可以进行双轿厢重置,即经过该类重置后的电梯井内存在两辆电梯,分别在划定的上、下两区中移动,且都可以进入换乘层,如何避免双轿厢电梯在换乘层相撞,设计上是这样实现的:

Step1 新建换乘楼层类TransferFloor,确保该类是线程安全的,可以被A/B电梯正确地修改。对于经过双轿厢重置的“电梯”(保留初始时电梯序号的概念,实际上描述为“电梯井”更加贴切),实例化一个TransferFloor对象,指示该电梯井中的换乘楼层是否被occupied,同时可以完成状态的set和release操作。

        public class TransferFloor {
            enum State { OCCUPIED, UNOCCUPIED }

            private State state;

            public TransferFloor() {
                this.state = State.UNOCCUPIED;
            }

           public synchronized void setOccupied();
           public synchronized void setRelease();
           private synchronized void waitRelease(); 
        }

Step2 对于双轿厢电梯,若经过移动操作到达换乘层,则执行setOccipied()操作,setOccupied()方法的具体实现是:

    public synchronized void setOccupied() {
        waitRelease();  //state为occupied则电梯wait,否则进入换乘层
        state = State.OCCUPIED; //进入换乘层,将换乘层状态设为occupied
        notifyAll();    
    }

Step3 为避免双轿厢电梯相撞,和电梯在需要时都可以顺利(或经过短时间等待后)进入换乘层,在本次设计中,不允许电梯在换乘层中驻留,即在电梯策略类中,若给出wait建议时电梯处于换乘层,则将该种情况下建议变为向远离换乘层方向移动,同时将换乘层状态变为unoccupied。这样就避免了某电梯长时间占据换乘层,另一电梯无法进入或相撞的情况。

bug相关

  • 轮询导致的CTLE
    由于轮询不会出现显式的正确性问题,所以在设计中很可能“大意致轮询”,甚至几乎在三次作业中第一次提交时都会出现或多或少的CTLE。
    虽然利用所获得的测试用例,轮询问题通过在每个线程中使用“print大法”很容易复现并确定问题所在处进行修复,但我认为这更多地是在提醒我在设计时总是过于“现实”,只考虑浅层的实现正确性,至于复杂度、CPU利用率等问题则置若罔闻,认为无论多丑陋只要能完成就是成功。但我想应该抛弃这种肤浅的“成功论”,无论是在OO还是OS课程中,我们都能了解到线程概念提出的初衷,而轮询行为却降低了CPU的利用率,所以该wait时就wait,避免CPU空转。
  • 线程无法正确结束
    由于迭代后期出现reset等操作,在确定线程是否可以终止时需要考虑的因素变多,所以hw6中电梯线程常常不能正确退出。
    该问题一般是由于调度器出现问题,没有正确地给每个电梯的候乘表setEnd,具体来说在判断reset请求是否处理完全时出现线程安全问题,更加保险地是利用候乘表这个线程安全类维护一个变量指示剩余未完成的reset数量,确保该变量的读取和修改都是线程安全的即可。
    也可能是因为在电梯得到wait建议但执行wait前被setEnd,但电梯最终进入wait而无法被唤醒,所以在执行wait操作前要确保候乘表为空但未结束,不能单凭策略类给出的建议。
    这一bug需要正确理解线程安全,梳理代码逻辑,找到问题所在,当然也可以通过输出电梯最终的状态信息帮助找到bug出现的原因。
  • “5 reset”问题
    “5 reset”在hw6互测中大杀四方,未能幸免。通过观察样例和输出很容易明白是由于分配时选择跳过正在重置的电梯,导致请求最终只落在一个电梯上,最终超时。要解决这个问题,只需要给每个电梯增加一个buffer,用于存储在重置时被分配到的请求(不输出receive),在重置完成后,将buffer中的内容加入到电梯候乘表中(此时输出receive)清空即可。选择“分配时跳过正在重置的电梯”这一设计还是过于“思维简单”,是一种典型的偷懒做法,没有考虑到特殊情况下可能出现的问题。

心得体会

  • 线程安全角度
    • 共享对象:利用sychronizednotifyAll()保证对共享对象的访问和修改行为是线程安全的,该方法在实现上也比较简便,实验中还提供了基于读写锁的实现方式。
    • 线程的结束条件:在这里犯了很多错误,可以说在初期对多线程的线程运行状态并没有正确领悟,在设计上还是习惯于按原来单线程的思路。所以在后期在设计的时候就开始反复问自己“这样会不会出现线程安全问题”,提醒自己要摒弃固有思维,正确地理解多线程。
  • 层次化设计
    经过Unit 1的训练,设计时会有意识地抽象出层次结构。要实现多线程实时电梯系统,可以将任务工程划分给不同的功能模块,并进行模块间接口的设计,最终自上而下地实现。
  • 受限于个人能力,在过去三周中遇到过很多的问题,最终的解决离不开每一位帮助过我的朋友们,在此特别感谢大家。
...全文
82 回复 打赏 收藏 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
大气污染是影响公众健康与生态环境的重要问题,精准的空气质量时空预测与污染源贡献度量化是精准治污的关键支撑。针对现有研究多源融合不充分、时空关联刻画不足、预测与源解析割裂三方面缺陷,本文设计实现了城市空气质量时空预测与污染源贡献度分析系统,融合监测、气象、工业排放与交通四类数据,构建基于时空注意力的LSTM(STAM-LSTM)预测模型与基于正定矩阵因子分解(PMF)的源解析模型,形成数据融合-特征工程-预测-源解析-可视化闭环。 系统实现四类数据时空对齐与融合,构建时序与空间邻域特征,以普通克里金插值生成1km网格浓度场;STAM-LSTM引入时空注意力自适应学习站点间污染传输时变权重,以72小时输入预测未来24小时逐小时PM2.5浓度;PMF识别交通、工业、燃煤、扬尘与二次生成五个源因子,量化各源全年贡献度并分析时空演变。 实验表明:STAM-LSTM预测RMSE 24.6、MAE 17.8、R² 0.88,相对LSTM基线(30.2)提升18.5%;普通克里金插值误差8.9,优于反距离加权(11.4);源解析显示交通源28.4%、工业源23.1%、燃煤源19.6%为主要贡献源,冬季燃煤源升至27.3%、早高峰交通源达34.8%,下风向工业源贡献高出上风向8~12个百分点;减排情景显示交通源减排20%可使年均PM2.5下降5.7%,与源贡献度排序一致。 系统按五模块14组件实现,功能测试16项用例全部通过,为大气污染预警、源管控与减排政策制定提供了决策依据。 【课程报告内容】 摘要 第1章 绪论 第2章 相关技术与理论 第3章 系统需求分析 第4章 系统总体设计 第5章 系统详细设计与实现 第6章 系统测试与分析 第7章 总结与展望 参考文献 附件-实现指南
基于iTransformer-BiGRU-KAN多模型融合的滚动轴承剩余寿命预测研究(Python代码实现)内容概要:本文提出了一种基于iTransformer-BiGRU-KAN多模型融合的滚动轴承剩余寿命预测方法,旨在通过结合多种先进深度学习模型的优势,提升在复杂工况下的预测精度与鲁棒性。该方法利用iTransformer捕捉长期时间序列中的全局依赖关系,通过BiGRU模型提取双向时序特征,最后引入KAN(Kernel Attention Network)增强非线性映射与关键特征的自适应加权能力,实现对轴承退化过程的精准建模。文中详细介绍了模型架构设计、训练流程及在公开数据集上的实验验证,结果表明该融合模型相比单一模型在预测精度和稳定性方面均有显著提升。; 适合人群:具备一定机器学习与深度学习基础,从事设备故障诊断、工业大数据分析或智能运维相关领域的研究人员及工程技术人员,尤其适合研究生及以上学历或有相关项目经验的专业人员。; 使用场景及目标:①应用于工业设备状态监测与预测性维护系统中,实现对滚动轴承等关键部件剩余寿命的精准预测;②为复杂时间序列回归任务提供多模型融合的设计思路与技术参考;③推动深度学习在智能制造与工业物联网领域的落地应用。; 阅读建议:建议读者结合Python代码实现部分,深入理解各子模型的接口设计与融合逻辑,重点关注特征融合机制与注意力权重的可视化分析,以便在实际项目中灵活调整与优化模型结构。

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧