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. Android 获取apk的URL Schemes

    1. 下载apk到你的PC上 2. 反向工程Android APK文件的工具 Apktool 3. 查看"AndroidManifest.xml"文件 See alse: http ...

  2. VAST生态驱动下,NGK算力增量效应初现!

    VAST维萨币上线的消息放出来之后,NGK算力的价格一直在上涨,其实这也不难理解,因为VAST维萨币需要VAST星光值进行兑换,VAST星光值又需要SPC算力福利代币进行挖矿释放的,SPC算力福利代币 ...

  3. Java 动态调试技术原理及实践

    本文转载自Java 动态调试技术原理及实践 导语 断点调试是我们最常使用的调试手段,它可以获取到方法执行过程中的变量信息,并可以观察到方法的执行路径.但断点调试会在断点位置停顿,使得整个应用停止响应. ...

  4. Ajax的基本用法

    1.介绍 2.基本用法 2.1原生写法 $.ajax({ url: url, //是否是异步请求,默认是 // async: false, //请求方式,默认是get //type:'get', // ...

  5. win10 查看已保存的wifi密码

    netsh wlan show profile name="WIFINAME-Test" key=clear   C:\windows\system32> C:\window ...

  6. java与freemarker遍历map

    一.java遍历MAP /** * 1.把key放到一个集合里,遍历key值同时根据key得到值 (推荐) */ Set set =map.keySet(); Iterator it=set.iter ...

  7. Qt+opencv亲自配置教程

    了别人的配置,总是无法配置成功,自己慢慢摸索配置成功.我失败的原因是在于自己本机的环境变量和他们不同,特此记下,分享给有相同问题的朋友. 一.需要软件 1.cmake 3.11.3(版本无所谓) 2. ...

  8. 解决 DatePickerDialog 在 Android7.0 API24 上使用 AlertDialog.THEME_TRADITIONAL、AlertDialog.THEME_HOLO_DARK、AlertDialog.THEME_HOLO_LIGHT等样式时无法显示为 Spinner 样式的问题

    DatePickerDemoForAndroid24 解决 DatePickerDialog 在 Android7.0 API24 上使用AlertDialog.THEME_TRADITIONAL.A ...

  9. 使用python进行接口自动化测试,批量执行测试用例

    工作中,使用python的requests库进行接口自动化测试是一个比较不错的选择,今天就以某网站的免费接口为例,展示以get请求进行批量执行测试用例.话不多说直接开讲 分析一下接口信息, 请求地址: ...

  10. Zeebe服务学习3-Raft算法与集群部署

    1.背景Zeebe集群里面保证分布式一致性问题,是通过Raft实现的,其实这个算法用途比较广泛,比如Consul网关,也是通过Raft算法来实现分布式一致性的. 首先简单介绍一下Raft: 在学术界, ...