OO第二单元博客总结

于嘉奇-24373465 2026-04-29 21:45:15

第二单元(hw5-hw7)多线程电梯系统总结博客

一、三次作业的总体演进与我的实现主线

第二单元三次作业的核心都是“多线程实时电梯系统”,但难度是层层递进的:

  • hw5:以“多电梯并行+基本捎带”为主,重点是线程模型搭建与基础正确性。
  • hw6:加入临时检修(MAINT),核心从“会跑”变成“在动态约束下持续正确”。
  • hw7:加入双轿厢改造/回收(UPDATE/RECYCLE)与同井道协同,复杂度从多线程进一步升级为“多线程+多状态机+多资源竞争”。

我自己的实现路线是:

  1. 先把“输入线程—调度线程—电梯线程”的生产者/消费者骨架搭稳;
  2. 再把RECEIVE约束、维护流程、乘客中转这些正确性问题逐步补齐;
  3. 在hw7中引入井道状态总管,把“局部电梯逻辑”提升为“井道级协同逻辑”。

二、同步块设置与锁选择:三次作业的总结与对比

1.锁结构

三次作业中,核心共享对象与锁大致可分为四类:

  1. 队列锁:保护请求队列、结束标志、wait/notify协作。
  2. 乘客映射锁:保护“乘客ID->电梯ID”的RECEIVE映射。
  3. 载重锁:保护电梯内乘客列表与总重量,保证上下客与载重判断一致。
  4. 井道状态锁(hw7新增):保护双轿厢模式、F2占位令牌、特殊流程占用状态。

2. 同步块与业务语句的关系

锁不是给“代码块”加保险,而是给“状态不变量”加保险。

(1)队列锁:保证“检查条件+等待/唤醒+取出请求”的原子性

在调度器/电梯线程中,典型结构是:

  • while(队列空&&未结束)wait
  • 条件满足后取请求

这要求“看条件”和“睡眠”在同一把锁下,否则会出现“刚检查完为空就错过通知”的经典竞态。

(2)映射锁:保证RECEIVE语义的一致性

RECEIVE 的关键是:同一乘客在同一阶段只能归属一个电梯。若多个线程交错清理/写入映射,容易出现重复RECEIVE、无法重新RECEIVE等错误。hw6/hw7中对映射的增删都做了集中同步,避免了这个问题。

(3)载重锁:保证“门状态与载重约束”一致

关门前必须满足载重约束。上下客会改变总重,因此“上下客修改总重”与“关门前检查总重”必须通过同一个同步对象协调。这样才能保证不会出现“刚判断可关门但实际已超重”的瞬时不一致。

(4)井道锁(hw7):保证双轿厢不冲突

hw7 的关键资源是同井道F2。两个轿厢都想进入/占用F2时,必须有互斥规则。通过井道状态管理器统一维护占位令牌并使用wait/notify,才能避免“同层冲突”与“互相等待”。

3. 三次作业锁策略的演进

  • hw5:以队列同步为主,锁粒度较粗,目标是“先正确跑起来”。
  • hw6:增加维护状态后,锁开始围绕“状态转移一致性”设计(RECEIVE清理、重分配、退出时机)。
  • hw7:进入“多资源协同”,除了线程安全,还要做资源调度安全(井道、换乘层、主备轿厢启停)。

三、调度器设计、线程交互与调度策略(含性能指标适配)

1. 调度器设计的三次迭代

hw5:指定电梯,调度器近似“转发器”

输入已给BY-电梯ID,调度器主要负责:

  • 从全局队列取请求;
  • 输出RECEIVE;
  • 投递到指定电梯队列。

hw6:自主分配+检修绕行

调度器职责升级为:

  • 自主选择电梯(轮转+跳过维护中/待维护电梯);
  • 跟踪MAINT进行数,避免“输入结束但维护未结束”时提前停机;
  • 处理中途下客/维护清客后的重新分配。

hw7:井道级调度+主备轿厢协同

新增能力包括:

  • 根据请求楼层区间和井道模式(单/双)分配主轿厢或备用轿厢;
  • 对 MAINT/UPDATE/RECYCLE统一做“特殊流程计数”,保证系统退出时机正确;
  • 跳过特殊占用井道,降低“分给不可服务对象”的概率。

2. 调度器与线程交互

系统线程交互链路大体是:

  1. InputProcessor读取请求,写入全局队列;
  2. JobDispatcher 从全局队列消费后,写入电梯专属队列;
  3. LiftHandler 执行运动/开关门/上下客;
  4. 若中转、检修、改造等导致请求未完成,电梯线程再把请求回流到全局队列,由调度器二次分配。

这是典型“多阶段生产者-消费者 + 回流”的架构。

3. 调度策略与性能指标的适配

课程性能指标核心是运行时间、平均完成时间、耗电量。在策略上的取舍是:

(1)时间指标

  • 尽量将请求分配给当前可服务的井道/轿厢,减少无效等待;
  • 特殊流程优先入队,缩短维护/改造响应时间;
  • hw7 中主备轿厢按楼层区间服务,减少跨区折返。

(2)电量指标

  • 在同次开门窗口内批量完成上下客,减少额外开关门;
  • 避免空跑(无有效请求不启动移动);
  • 双轿厢后通过分区服务减少长距离无效移动。

(3)多指标平衡

若过度追求最短等待,可能导致频繁停靠和开关门;若过度省电,可能增加平均完成时间。我的策略更偏“稳健中庸”:

  • 先保证正确性和退出安全;
  • 在此基础上减少明显空跑与冲突;
  • 不做过度激进、易破坏线程安全的优化。

四、出现过的bug与我的多线程debug方法

1. 我遇到/重点处理过的典型bug

调度器提前退出(hw6)

现象:输入结束且全局队列短暂为空时,调度器退出;但此时某电梯仍在维护流程,后续还会回流未完成乘客,导致请求无人处理。

本质:退出条件没有把“系统动态状态(维护中/特殊流程中)”纳入判定。

修复思路:退出条件加入维护/特殊流程计数输入结束联合判定。

维护开始后未进电梯乘客处理不完整

现象:MAINT1-BEGIN后,部分已分配但未上车的乘客没有被正确回流,导致“逻辑上存在请求,系统中却丢失”。

本质:RECEIVE结束与请求实体回流没有同步完成。

修复思路:清理RECEIVE映射+回流全局队列+唤醒调度器。

RECEIVE映射残留

现象:乘客已中途下车,但映射未清理,后续不再输出新的 RECEIVE,触发约束错误。

本质:状态机推进了,映射状态没推进。

修复思路:中转下车、维护清客、改造/回收清客都统一调用清理逻辑。

双轿厢 F2 协同冲突(hw7)

现象:主备轿厢在 F2 发生竞争,轻则等待放大,重则相互卡住。

本质:共享资源(F2)没有统一仲裁器。

修复思路:引入井道状态管理器 + F2占位令牌 + 让行机制。

2. debug 方法

  1. 先做状态机对账,不先盯代码细节:把请求从输入到完成的完整链路写成时序图,先找“状态断裂点”。
  2. 构造最小复现数据:少量请求+精确时间戳,专打一个条件(如“输入刚结束+维护未结束”)。
  3. 加结构化日志而不是乱打日志:按“线程名/请求ID/状态转换前后”打印。
  4. 关注不变量:如“RECEIVE映射存在 <=> 乘客有当前归属”;任何违反都立即追踪。
  5. 回归测试分层做:先单电梯,再多电梯,再维护,再双轿厢,最后混合压测。

五、对“线程安全 + 层次化设计”的理解

线程安全:不是“全都加锁”,而是“定义所有权”

  • 谁拥有状态,谁负责修改;
  • 跨线程共享状态越少越好;
  • 必须共享时,围绕不变量设计锁边界。

比如电梯运行细节尽量由电梯线程单写,调度器不直接改电梯内部细节;调度器只通过队列和少量状态接口交互。

层次化设计:把“策略”和“动作”分开

当前系统拆成:

  • 输入层(InputProcessor)
  • 分派层(JobDispatcher)
  • 执行层(LiftHandler)
  • 规则/状态层(LiftController、ShaftStateManager)
  • 细节服务层(PassengerManager、DoorOperator、FloorMovement、LiftPassengerFlowService)

这样做的好处是:

  • 新需求(MAINT/UPDATE/RECYCLE)可以落在相对独立的层;
  • 修改冲击面更小;
  • debug 时能快速定位是“决策错”还是“执行错”。

六、大模型使用心得(我使用 Copilot 辅助)

1. 模型与分工

本单元主要使用GitHub Copilot做辅助。我的分工是:

  • 我负责题目概念理解、状态机设计、代码测试和debug、设计优化策略;
  • Copilot负责样板代码补全、重构建议、增删代码注释、代码风格优化等。

整体来讲,大模型是“副驾驶”,不是“自动驾驶”。

2. 大模型优势

面对多线程电梯这类复杂任务,大模型信息整合速度快,而且面对大量代码量可能导致的基础错误有很好的纠错能力;此外重构效率高,hw7为了代码风格重构LiftHandler类时,把大类拆服务类时很省时间。
此外,能快速产出代码架构梳理,分析报告、测试方案骨架,节省很多时间。

3. 大模型缺陷

最大问题是模型记忆功能还是不够完善,直接vibe coding会出现一些意想不到的低级错误,离不开人工测试和逻辑补完()。而且大模型面对一些细化的bug时,debug策略不是很好,还是要靠人力。

七、第二单元真实体验、感受与建议

这一单元是我在OO课程里压力最大的阶段之一(中间hw6进了一次o房心态很爆炸)。难点主要在规则多、状态多、线程多;bug不稳定复现;小改动会引发连锁反应等等。

但也吸取了很多教训,比如意识到写一个性能良好的评测机真的很重要()。

结语

回看hw5到hw7,最大的变化不是“写了更多代码”,而是开始真正理解:

  • 多线程系统首先是状态系统,其次才是代码系统;
  • 线程安全首先是边界设计,其次才是同步语法;
  • 性能优化首先是正确性稳定后的工程迭代。

第二单元确实很难,但也确实让我在并发编程、系统分层与工程思维上迈过了一个关键台阶。

...全文
20 回复 打赏 收藏 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

309

社区成员

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

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