BUAA_OO_2020_UNIT2

一、程序结构分析

  • 第五次作业

    UML & Mertrics

    ​ 电梯的调度问题,实质上就是任务的请求与分配问题,笔者在第五次作业中采用简单的“生产者-消费者”模型,建立了Din线程作为生产者解析输入并增加运载请求,建立Elev线程进行输出,待处理数据由主控类Ctrl维护,并作为电梯“调度器”,前两者的操作由线程安全的Ctrl负责,后两次作业也延续这样的架构,事实是无需重构也应付得了本次迭代。但笔者请求队列与调度器一体化,且只有一级调度,导致主控类异常臃肿。

  • 第六次作业

    UML & Mertrics

    ​ 仍是老三样,第六次作业中扩展功能比较容易实现,进行相关类的方法扩写,主要是实现多电梯线程,笔者Ctrl类的处理不是很好,下一次重写了Ctrl

  • 第七次作业

    UML & Mertrics

    ​ 架构上没有大的改动,为实现换乘功能,笔者建立了MyReq类存储PersonRequst与乘客现处楼号,并面向过程根据换乘地图为各型电梯建立了楼层映射机制

二、Bug分析

  • 第五次作业中主要遇到的是多线程初见的线程调度bug,主要是笔者当时没有找到精准的notify()条件,居然唤起了RUNNALBE的线程,由于Ctrl是共享的,导致输入被电梯线程阻塞,好在最终确定了进入wait()的条件。
  • 第六次作业笔者体会到了线程安全问题在本单元的重要性,在处理电梯数目输入时,笔者竟然没用输入文档的ElevatorInput.getElevatorNum(),而是用(new Scanner(System.in)).nextInt(),System.in被输入接口与Scanner共享,导致输入缓冲区线程不安全,笔者这次属实拉了胯了,直接白给愉悦送走
  • 第七次作业又出现了恶性bug,当C型电梯上的乘客想去楼4时,笔者直接给他送到楼3,但楼3只有C能去,B接不到,这次强测也是差点翻车了,不过三次作业笔者的整体结构还是可以的,通过严格控制synchronized语句块的分布与使用,三次作业除了这些bug也没有出现过死锁或是数据冒险啥的难以复现的bug

三、互测策略

  • 第五次作业功能比较简单,只要保证简单的线程调度就只用考虑单电梯调度问题,可以输入30条从底楼到顶楼的数据测试他人是否完成了捎带
  • 第六次没进互测,不过笔者认为可以从电梯超载与输入指令数最大化这两方面进行hack
  • 第七次重点在于线程安全与换乘,可以输入仅1条需要换乘的指令,测试他人是否在换乘完成前相关电梯线程已退出,更可以围绕换乘问题,观察三类电梯楼号的定义域可以发现1,3,15是最特殊的3个换乘点,也可以枚举所有请求后排除直达请求进行换乘的完备hack

四、对象创建模式

  • 第五次作业只建立了输入线程Din,电梯线程Elev,看到一些朋友把调度器也整成线程我是没想到的,Din负责向Ctrl输入数据,并在输入及结束后唤醒所有WAITINGElevElev的结束条件是没有待调度请求并且Din在结束后设置了无输入的全局变量。具体调度策略方面,选用LOOK算法,但无论SCAN还是LOOK,都损失了一个方向上的请求信息,总感觉不太好。于是之后笔者就真香GREEDY了,打造了纯贪心的电梯调度与电梯间调度策略

  • 第六次作业改动不多,主要是改变了Ctrl中的数据结构适配多部电梯,另外的重头戏就是电梯间调度,笔者在本次将单电梯改为贪心电梯,与同学交流中有的是用平均分配、随机分配来分派任务到各个电梯,但笔者还是采用了电梯间自由地贪心竞争策略。原因是,设想有两架Elev,一台空载,一台载有乘客,从同一楼号出发,对于某一请求而言,载人Elev因为电梯内请求而停靠或转向的平均概率更高,空载更有可能抢到请求。实际上载客越少越能直接相应电梯外请求,这有效减小某些电梯一直空转的几率,从而自动实现了优先级任务分配,提高了Elev并行率,每次上一个人也可以Thread.sleep(5)提高并行率。还有就是这样不用写二级调度了

  • 第七次作业,鉴于要实现换乘,有必要维护需要换乘乘客的当前楼号,于是笔者新建了MyReq类改进PersonRequst,对于上文二、notify了运行线程的bug,笔者也找到了安全方便的方案

    for (int i = 0; i < elevNum; i++) {
    if (elevs.get(i).getState().equals(Thread.State.valueOf("WAITING"))) {
    synchronized (elevs.get(i)) {
    elevs.get(i).notifyAll();
    }
    }
    }//先判断是在wait()再notifyAll();

    同时要注意线程安全的坑,笔者是保证所有Elev最后一起DEAD的,防止要换乘的电梯早退

    解决线程设计后,烦人的换乘问题来了,各型电梯的楼号定义域A = [-3, 1] ∪ [15, 20],B = [-2, 15] - {3}C = [1, 8] * 2 - 1,找到换乘点(A ∩ B) ∪ (A ∩ C) ∪ (B ∩ C) = (C - {3}) ∪ {-1, -2},笔者并不想写二级调度,就建立了地址转换,考虑ElevMyReq的解析,我们只要在电梯A-C下完成MyReq在电梯内和在电梯外的楼号转换就行,实际上完成前者就行,若电梯内getToFloor()非法,就将目的地改为换乘路径最短的换乘点。电梯外的话,先假设上电梯,转换后若目标就是当前楼层,就保留原本目的地,否则直接上电梯。笔者真是懒死了,这类特定情境问题还是最好编程打表,别像笔者败在细节。

五、心得体会

​ 笔者本单元的作业效果并不理想,还是对于线程安全的理解不深,以及没有注重多线程程序设计中的细节问题导致bug,笔者还是对自己的调度器耿耿于怀,笔者理应实现队列,调度分离的,这样的调度器耦合度太高了。

BUAA_OO_第二单元的更多相关文章

  1. OO第二单元作业小结

    前言 转眼已是第九周,第二单元的电梯系列作业已经结束,终于体验了一番多线程电梯之旅. 第一次作业是单电梯的傻瓜调度,虽然是第一次写多线程,但在课程PPT的指引下,写起来还是非常容易:第二次作业是单电梯 ...

  2. BUAA面向对象设计与构造——第二单元总结

    BUAA面向对象设计与构造——第二单元总结 第一阶段:单部傻瓜电梯的调度 第二阶段:单部可捎带电梯的调度 (由于我第一次写的作业就是可捎带模式,第二次只是增加了负数楼层,修改了一部分参数,因此一起总结 ...

  3. 我永远爱着OOP——第二单元作业总结

    第二单元的电梯真是愉♂快呢,多线程编程作为java编程OOP中的重要组成部分,通过这一个单元的学习,我也是有了很多全新的认识 那么下面就先例行一下公事 三次作业分析 第五次作业 设计分析 实现的电梯是 ...

  4. 2019OO第二单元总结

    (1)设计策略 电梯第1次作业是一个傻瓜调度电梯,使用先来先服务原则,不用考虑捎带(可以认为电梯的载客量为1),因此比较简单,调度器用一个队列就可以. 使用生产者-消费者模型,输入线程是生产者,电梯是 ...

  5. oo第二单元作业总结

    oo第二单元博客总结 在第一单元求导结束后,迎来了第二单元的多线程电梯的问题,在本单元前两次作业中个人主要应用两个线程,采用“生产者-消费者”模式和共享数据变量的方式解决问题.在第三次作业中加入多个电 ...

  6. OO第二次博客作业--第二单元总结

    第一次作业 1. 设计策略 第一次作业,一共三个线程,主线程.输入线程和电梯线程,有一个共享对象--调度器(队列). 调度的策略大多集中到了电梯里,调度器反而只剩下一个队列. 2. 基于度量的分析 类 ...

  7. 第二单元电梯调度作业 By Wazaki

    figure:first-child { margin-top: -20px; } #write ol, #write ul { position: relative; } img { max-wid ...

  8. OO第二单元总结(多线程的电梯调度)

    经过第一单元作业的训练,在做第二单元的作业的时候,要更加的有条理.但是第二次作业多线程的运行,带来了更多的运行的不确定性.呈现出来就是程序会出现由于线程安全问题带来的不可复现的bug.本单元的作业也让 ...

  9. OO第二单元电梯线程系列总结作业

    电梯系列第一次作业 功能描述: 傻瓜电梯无需考虑超载捎带 线程模式: Producer-Consumer Pattern 思路: 第一次作业是一个傻瓜电梯,分别有一个生产者生成电梯指令(也就是Inpu ...

随机推荐

  1. 我眼中的价值币——NGK(下)

    跨链交互方案并不是区块链世界中的一个新课题.自比特币诞生揭开智能合约的序幕之后,跨链交互的需求便产生了.但是,经过十年的发展,市场中的跨链解决方案进展缓慢,究之原因有以下几个方面. 首先,区块链的去中 ...

  2. Hive底层原理:explain执行计划详解

    不懂hive中的explain,说明hive还没入门,学会explain,能够给我们工作中使用hive带来极大的便利! 理论 本节将介绍 explain 的用法及参数介绍 HIVE提供了EXPLAIN ...

  3. Jmeter beanshell编程实例

    1.引言 BeanShell是一种小型的,免费的,可嵌入的符合Java语法规范的源代码解释器,具有对象脚本语言特性. 在Jmeter实践中,由于BeanShell组件较高的自由度,通常被用来处理较为复 ...

  4. servlet内置对象(传递数据)

    一个servlet向另一个servlet发送数据,可以将数据放置在一个容器中(io.数据库.servlet的内置对象),servlet的内置对象成本最小. 一共有三个内置对象. 名字 类型 reque ...

  5. 搭建SSH框架

    以下为链接地址:https://www.2cto.com/kf/201606/518341.html

  6. SpringBoot接收map类型的参数

    如果某个controller的某个接口的参数特别多,也可以使用map的方式来接收参数,接收之后使用get方法获取即可. 1)get请求方式,定义map接收方式 @RequestParam(requir ...

  7. MySQL如何搭建主库从库(Docker)

    目录 MySQL主从搭建 一.主从配置原理 二.操作步骤 1.创建主库和从库容器 2.启动主从库容器 3.远程连接并操作主从库 4.测试主从同步 MySQL主从搭建 一.主从配置原理 mysql主从配 ...

  8. js中数据、内存、变量的概念及三者之间的关系

    目录 数据.内存.变量的概念及三者之间的关系 什么是数据 数据的特点 什么是内存 栈内存 堆内存 JS引擎如何管理内存 什么是变量 变量是普通类型时 变量是引用类型时 数据.内存.变量的三者之间的关系 ...

  9. 从零搭建一个IdentityServer——单页应用身份验证

    上一篇文章我们介绍了Asp.net core中身份验证的相关内容,并通过下图描述了身份验证及授权的流程: 注:改流程图进行过修改,第三方用户名密码登陆后并不是直接获得code/id_token/acc ...

  10. Azure Front Door(二)对后端 VM 进行负载均衡

    一,引言 上一篇我们讲到通过 Azure Front Door 为我们的 Azure App Service 提供流量转发,而整个 Azure Front Door 在添加后端池的时候可选的后端类型是 ...