304
社区成员
发帖
与我相关
我的任务
分享本单元电梯作业核心是多线程安全协作,三次作业迭代中,我围绕wait/notify、ReentrantLock、synchronized三种同步机制,逐步优化锁粒度与同步块逻辑,保证线程安全且避免轮询、死锁。
电梯井状态机同步:ElevatorShaft中状态切换、紧急请求接收(检修 / 改造 / 回收)均用synchronized (this)包裹,保证状态原子性修改与wait/notify安全唤醒。
电梯线程等待唤醒:Elevator run () 方法中,用synchronized (this)包裹等待条件判断,避免多线程同时修改emergencyStop、isWaiting等状态。
调度器请求分发:Scheduler的dispatchRequest、reDispatchRequests加synchronized,防止多线程同时分配请求导致重复 RECEIVE。
电梯移动互斥:Elevator中moveLock保护电梯移动逻辑,避免双轿厢模式下两部电梯同时修改楼层、触发碰撞。
电梯开关门互斥:operationLock保证开门、关门、乘客进出的原子性,满足 “开门至少 0.4s” 的约束。
请求队列安全:RequestQueue用ReentrantLock+Condition实现生产者 - 消费者,替代synchronized,更灵活控制等待与唤醒。
锁粒度最小化:同步块仅包裹共享变量读写与原子操作,不包裹Thread.sleep()、电梯移动等耗时操作,避免长期占锁导致性能下降。
wait/notify 必须在同步块内:所有wait()、notify()均在synchronized内部,防止IllegalMonitorStateException。
共享变量必须加锁:电梯楼层、乘客队列、状态机状态等全局共享数据,读写必加锁,保证多线程可见性与原子性。
避免嵌套锁死锁:严格控制锁的获取顺序,如先锁电梯井、再锁电梯对象,不循环依赖锁。
第五次作业:无智能调度,仅按输入指定电梯分发请求,调度器为 “空壳转发器”。
第六次作业:新增检修请求,调度器增加电梯可用性判断,检修中的电梯不分配请求。
第七次作业:支持双轿厢改造 / 回收,调度器新增电梯井可用轿厢筛选,根据乘客起终点分配主轿厢 / 备用轿厢。
最终架构:Scheduler作为中央调度器,持有全部电梯井引用,统一接收乘客请求,按策略分配到最优电梯。
输入线程→调度器:InputThread读取输入,将乘客请求交给dispatchRequest,紧急请求直接发给对应电梯井。
调度器→电梯线程:调度器选中最优电梯后,调用addRequest加入队列,并notifyAll()唤醒等待的电梯线程。
电梯线程→调度器:电梯检修 / 改造 / 回收时,清空未完成请求,调用reDispatchRequests交回调度器重新分配。
状态机→调度器:电梯井状态切换完成后,调用reDispatchPendingRequests分配暂存请求。
我的核心调度策略:负载优先 + 距离最优评分公式
score = 电梯总请求数 × 3 + 电梯当前楼层到起点楼层距离
适配时间指标:优先分配负载低、距离近的电梯,减少电梯空跑、缩短乘客等待时间,降低总运行时间。
适配电量指标:减少不必要的 ARRIVE、OPEN、CLOSE,降低移动层数与开关门次数,节约耗电量。
双轿厢适配:getAvailableCars按楼层范围分配,主轿厢服务 F2-F7,备用轿厢服务 B4-F2,避免跨范围无效分配。
紧急场景适配:检修 / 改造 / 回收时,自动释放请求并重新调度,不阻塞整体流程。
轮询 CPU 超标:初期用while(true)空转判断队列是否为空,CPU 时间超 10s。
修复:改用wait/notify,无任务时线程休眠,不占用 CPU。
死锁:嵌套获取电梯锁与电梯井锁,顺序不一致导致循环等待。
修复:统一锁获取顺序,先锁电梯井,再锁电梯对象。
重复 RECEIVE:多线程同时分配同一乘客,输出多条 RECEIVE。
修复:PassengerManager标记乘客接收状态,调度器加synchronized。
双轿厢碰撞:两部电梯同时到达 F2,违反 “不同时同层” 约束。
修复:isCollisionPossible判断冲突,强制一部电梯避让。
线程无法退出:请求结束后电梯线程仍在wait(),程序不结束。
修复:RequestCounter计数为 0 时,唤醒所有电梯线程。
日志定位:用TimableOutput输出关键状态(锁获取 / 释放、wait/notify、状态切换),还原线程执行顺序。
单线程调试:先关闭多线程,用单线程跑通逻辑,再逐步开启并发。
查看线程状态:用 IDEA 调试工具查看线程是否阻塞、死锁、等待。
最小化复现:用简单用例复现 Bug,避免复杂数据干扰。
共享变量检查:所有共享变量必须加锁,逐行检查是否有线程不安全读写。
线程安全不是 “加锁越多越好”,而是合理控制共享资源访问:
原子性:一系列操作要么全部完成,要么不执行,用锁保证。
可见性:一个线程修改共享变量,其他线程能立即看到,用synchronized或volatile保证。
有序性:避免指令重排导致逻辑错误。
本单元中,乘客队列、电梯状态、状态机状态是核心共享资源,全部用锁严格保护。
我采用四层架构,层次清晰、易于迭代:
输入层:InputThread读取输入,分发请求。
调度层:Scheduler统一分配请求,协调全局资源。
电梯井层:ElevatorShaft管理状态机,控制主 / 备用轿厢。
电梯层:Elevator执行开关门、移动、乘客接送。
优势:
职责单一:每层只做一件事,便于修改与维护。
迭代友好:第六次加检修、第七次加双轿厢,只需修改对应层,不影响整体架构。
线程隔离:每层线程独立通信,通过方法调用交互,降低耦合。
主要使用豆包,deepseek和lingma完成本单元作业。
我负责:整体架构设计、锁与同步块规划、调度策略制定、Bug 定位与修复、代码逻辑验收。
大模型负责:
多线程语法规范检查,提示wait/notify、ReentrantLock使用细节。
生成模板代码,如RequestQueue、PassengerManager等工具类。
解释死锁、轮询、可见性等多线程概念,辅助理解原理。
快速生成状态机、调度逻辑的伪代码,提高编码效率。
快速查漏补缺:能精准指出锁遗漏、同步块错误、wait/notify位置不当等问题。
多线程概念讲解直观:用通俗语言解释复杂理论,降低学习门槛。
代码生成效率高:工具类、枚举、状态机框架可一键生成,节省重复编码时间。
Debug 辅助:根据报错信息与代码片段,快速定位线程安全问题。
无法完全理解作业细节约束(如 RECEIVE 规则、双轿厢楼层限制、检修时间约束)。
复杂调度策略需要人工调整,模型生成的策略难以直接满足性能要求。
多线程 Bug 复现环境复杂,模型只能给出通用思路,无法精准复现现场。
大模型是高效辅助工具,不是 “代做工具”。在多线程这种强逻辑、强规范的作业中,模型能帮我节省大量时间,但架构设计、策略优化、Bug 修复必须靠自己思考。使用模型后,我更专注于设计与逻辑,而非语法与细节拼写,学习效率大幅提升。
第二单元是 OO 课程难度跃迁的单元,从单线程直接进入多线程,初期被死锁、轮询、线程安全搞得很崩溃。但随着三次作业迭代,逐步理解了锁、线程协作、层次化设计的思想,最终写出稳定、高效的电梯程序,成就感很强。
多线程编程的核心是 控制共享,所有问题都源于资源竞争,所有解决方案都围绕 “有序访问” 展开。
增加多线程基础实验:在第五次作业前,增加简单的生产者 - 消费者小实验,降低入门难度。
提供锁与同步块示例:官方给出标准的线程安全队列、等待唤醒模板,减少学生踩坑。
性能指标说明更清晰:提前明确时间、电量的计算方式与优化方向。
多线程 Debug 教学:增加专门的 Debug 讲座,讲解日志、线程监控、死锁排查方法。
非常感谢课程组的设计,第二单元让我真正掌握了多线程编程的核心能力,收获极大!