2024 BUAA OO 第二单元总结

余欣实-22373040 学生 2024-04-20 00:25:08

目录

  • 一、三次作业的程序结构和度量分析
  • Homework1
  • 同步块的设置和锁的选择
  • 锁与同步块中处理语句之间的关系
  • 调度策略分析
  • Homework2
  • 同步块的设置和锁的选择
  • 锁与同步块中处理语句之间的关系
  • 调度策略分析
  • Homework3
  • 同步块的设置和锁的选择
  • 锁与同步块中处理语句之间的关系
  • 调度策略分析
  • 双轿厢的两个轿厢不碰撞的实现
  • 二、程序出现过的 bug 以及面对多线程程序的 debug 方法
  • 程序出现过的 bug
  • 多线程程序的 debug 方法
  • 三、心得体会
(2024 BUAA OO 第二单元总结)

一、三次作业的程序结构和度量分析

Homework1

  • 第一次作业架构的类图如下:

    img

  • 第一次作业架构的协作图如下:

    img

    同步块的设置和锁的选择

  • 第一次作业中主要用到了 synchronized 关键字和 wait()、notify() 方法来实现线程的同步与通信

    锁与同步块中处理语句之间的关系

  • Elevator 类中的 run() 方法中的 synchronized (startLock) 表示使用 startLock 对象作为锁,控制线程的启动与暂停。当收到信号时,线程会被唤醒并执行相应的任务
  • Schedule 类中的 startElevators() 方法中,使用了 synchronized (elevatorStartLocks.get(i)) 来对每个电梯的启动进行同步操作,确保同一时刻只有一个线程可以操作某个电梯的启动
    调度器设计与线程交互
  • 调度器负责管理多个电梯线程的运行,它会周期性地检查大厅输入是否结束,并根据电梯的状态和目标楼层来启动相应的电梯。调度器与电梯线程之间通过对象的锁和通知机制进行交互,确保电梯在适当的时候被唤醒并执行任务

    调度策略分析

  • 本次作业中的调度策略主要包括了:
    • 根据当前楼层和电梯状态来确定电梯的目标楼层,以最大程度地满足乘客请求
    • 调度器定期检查大厅输入是否结束,并根据电梯的状态来启动相应的电梯
    • 当所有电梯都完成任务后,调度器停止工作
    • 调度器的设计考虑了时间和性能指标,确保了电梯系统能够高效地运行,同时保证了线程之间的协调与同步

Homework2

  • 第二次作业架构的类图如下:

    img

  • 第二次作业架构的协作图如下:

    img

    同步块的设置和锁的选择

  • 在 Elevator 类中,使用了同步块和 startLock 对象,以确保线程安全地对电梯状态进行修改和通知其他线程。这样做的好处是可以避免多个线程同时修改电梯状态,保证状态的一致性
  • 在 Schedule 类中,使用了 elevatorStartLocks 对象作为电梯启动的锁,确保在调度过程中每个电梯的启动操作是同步的,避免冲突和混乱

    锁与同步块中处理语句之间的关系

  • 在 Elevator 类中,同步块包裹了对 startLock 对象的等待和通知操作,以及对电梯状态的修改操作,保证了这些关键操作的原子性和线程安全性
  • 在 Schedule 类中,对于每个电梯的启动操作都在同步块中进行,使用相应的 elevatorStartLocks 对象进行加锁和解锁,确保了每个电梯的启动操作是同步的

    调度策略分析

  • 调度策略涉及到根据当前电梯状态和大厅中的请求来确定每个电梯的运行目标,以最优的方式响应用户请求
  • 在 Schedule 类中,通过 calculateTarget 方法计算每个电梯的目标楼层,考虑了电梯当前位置、上行和下行请求的分布情况等因素,以及当前电梯的运行状态,实现了合理的调度策略
  • 通过监测大厅中的请求和电梯的状态,调度器动态地调整电梯的运行目标,以适应不同情况下的调度需求,提高了电梯系统的效率和性能
  • 该调度系统的设计考虑了多个性能指标,包括响应时间、电梯运行效率等。通过合理的调度策略和线程交互设计,系统能够在保证服务质量的同时,尽可能地提高运行效率,满足不同用户和场景下的需求
    • 例如,在 calculateTarget 方法中,根据当前电梯状态和大厅中的请求情况,动态地确定每个电梯的运行目标,以最小化用户等待时间和电梯运行时间
  • 此外,在 resetElevators 方法中,及时对电梯进行重置操作,以确保电梯的状态和参数能够及时更新,提高系统的稳定性和可靠性

Homework3

  • 第三次作业架构的类图如下:

    img

  • 第三次作业架构的协作图如下:

    img

    同步块的设置和锁的选择

  • 在 Hall 类中:
    • 在 addReset() 方法中使用了同步块,以保证多个线程对 resetSigns 集合的操作的互斥访问
    • 在 getReset() 和 removeReset() 方法中同样使用了同步块,以保证对 resetSigns 集合的读取和修改的原子性,使用 synchronized 关键字来锁定 resetSigns 对象
  • 在 Schedule 类中:
    在 resetElevators() 和 startElevators() 方法中,根据不同的情况使用了 synchronized 同步块,以保证对 elevatorStartLocks 对象的互斥访问
    使用 elevatorStartLocks 对象作为锁,保证对应电梯的状态修改的原子性

    锁与同步块中处理语句之间的关系

  • 锁和同步块的设置主要是为了保证对共享资源的并发访问的线程安全性。在 Hall 类中,通过同步块和锁来保护对 resetSigns 集合的读取和修改,以及在 Schedule 类中保护对 elevatorStartLocks 对象的访问
  • 处理语句在同步块中执行,这样可以保证同一时间只有一个线程能够访问共享资源,从而避免了并发访问导致的数据不一致或者竞态条件的问题
  • 调度器 Schedule 类负责管理电梯的调度工作,通过与 Elevator 类和 Hall 类的交互实现对电梯的控制
  • 调度器根据电梯的状态和楼层请求情况,决定每个电梯的行动目标,并通过通知对应的电梯线程来启动或者重置电梯的运行状态
  • 调度器通过与 Elevator 类的交互来控制电梯的运行状态,通过与 Hall 类的交互来获取楼层请求信息和重置请求信息

    调度策略分析

  • 该调度系统采用的是基于楼层请求情况和电梯状态的调度策略,根据当前电梯的位置、运行方向和楼层请求情况来决定电梯的运行目标
  • 在 calculateTarget() 和 calculateTargetForLast() 方法中,根据当前电梯的位置和楼层请求情况,计算出电梯的运行目标楼层和方向
  • 调度器根据不同电梯的状态和楼层请求情况来动态调整电梯的行动目标,以提高电梯系统的运行效率和响应速度
  • 对于适应性性能指标,该系统主要考虑了电梯的运行效率、响应速度和系统的稳定性,通过动态调整电梯的行动目标和重置电梯的运行状态来提高系统的适应性和性能表现

    双轿厢的两个轿厢不碰撞的实现

  • 通过对一个双轿厢电梯共享的原子变量 AtomicBoolean 作为锁进行线程控制,确保换乘楼层同时只有一部电梯出现

二、程序出现过的 bug 以及面对多线程程序的 debug 方法

程序出现过的 bug

  • 三次作业中我出现的 bug 主要来自于线程控制中的死锁问题:
    • 在调度器与电梯的互相唤醒过程中,我最初使用了两个独立的锁进行互相的获取与使用,但这一方法会在一些极特殊情况下出现双方都在等待对方交出锁的状况从而发生死锁
    • 对应的解决方法为,将原有的一对锁简化为一个锁,单一锁的使用与传递就自然而然地避免了死锁的发生

      多线程程序的 debug 方法

  • 多线程程序的 debug 方法主要有以下几种:
    • 日志记录:在代码的关键部分插入日志语句,输出线程 ID 和相关状态信息,可以跟踪执行流程并识别潜在问题,应用最为广泛
    • 线程转储:获取线程转储以查看程序中所有线程的状态。大多数编程语言和开发环境都提供生成线程转储的工具,分析线程转储可以识别死锁、线程争用和其他并发问题
    • 调试器:使用支持多线程调试的调试器。在代码的关键部分设置断点,并逐步执行以观察线程行为,尽管调试器会影响程序的运行,但在一些特定情形下同样也能发挥作用
    • 同步原语:直接对同步原语(如锁、信号量和条件变量)的使用情况进行检查,确保正确获取和释放锁,并安全地访问共享资源

三、心得体会

  • 在多线程编码与迭代中,线程安全和层次化设计是两个关键方面
  • 在多线程环境下,共享资源的安全访问至关重要。合理地使用锁机制可以确保在任何时候只有一个线程能够访问共享资源,从而避免竞态条件和数据不一致性的问题。锁的粒度应该尽可能小,以最大程度地减少锁的持有时间,提高并发性能。过大的锁粒度会导致线程之间的竞争增加,降低系统的并发性能。死锁是多线程编程中常见的问题,应该尽量避免。为了避免死锁,需要谨慎地设计锁的获取顺序,并确保在获取锁时不会产生循环依赖。在多线程编程中,应该优先选择线程安全的数据结构和库,以减少手动同步带来的复杂性和风险
  • 层次化设计有着诸多的设计原则,其目的在于降低系统的复杂度,提高代码的可维护性和可扩展性
    • 每个模块应该定义清晰的接口,以便于模块间的交互和协作,良好定义的接口能够降低模块之间的耦合度,提高系统的灵活性和可测试性
    • 使用分层架构可以将系统划分为多个层次,如表示层、业务逻辑层和数据访问层,每个层次都有明确定义的职责和接口,有利于提高系统的可维护性和可扩展性
    • 在层次化设计中,应该清晰地定义错误处理策略和异常传递机制,以便于快速定位和处理问题,并避免错误信息在不同层次间的混淆和丢失
    • 同时对于解耦合,设计时应该尽量降低模块间的耦合度,使得每个模块能够独立地进行开发、测试和部署,合理地使用依赖注入、事件驱动等技术可以帮助实现模块间的解耦合
  • 通过在多线程编码与迭代中的实践,我深刻体会到了线程安全和层次化设计在构建高效、可靠的多线程系统中的重要性。良好的线程安全策略和清晰的层次化设计可以有效地降低系统的复杂度和风险,提高系统的稳定性和性能
...全文
34 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

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

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