OO第二单元——多线程(电梯)

综述

第二单元的三次联系作业都写电梯,要求逐步提高,对于多线程的掌握也进一步加深。本次作业全部都给出了输入输出文件,也就避免了正则表达式判断输入输出是否合法的问题。

第一次作业——单部电梯(无调度)论述

第一次作业,是写一部电梯的模拟器,指导书提供了一个极为基础或者说不叫算法的算法,只需要将人送到正确楼层即可,对于时间、性能没有任何要求,但也是我们第一次尝试多线程,开始写代码时对于wait(),notify()函数并不是十分了解,导致出现了各种线程不安全,或是出现死锁的状况,代码写得也比较的复杂,架构并不是十分清晰。

性能分析

方法复杂度

明显可以看出run方法复杂度较高,其他方法为正常水平。

类复杂度

由于没有任何性能要求,我采取了接完一个人再去接另一个人的方法,效率极低,但可以保证正确性,建立了两个线程,一个Producer线程,负责读取输入,并放入共享队列中,另个一个Consumer线程,负责处理共享队列中的指令,并指导电梯上下移动,而在这次作业中我将电梯和Consumer写在了一起,也就是没有调度器线程,而只有生产者、消费者。

在后期,我也遇到了一些问题,比如结束程序的问题,我在Ctrl D后,并不能结束进程,而是卡在了一些死循环或是wait里,最终我也在用了信号量的情况下多加判断,结束进程。

第二次作业——单部电梯(ALS调度)论述

第二次作业,与第一次作业要求并无太大差别,只是增加了地下楼层,也就是负数楼层, 但在性能上有所要求,指导书给出了ALS算法,即捎带算法,在电梯运行过程中捎带路过楼层的乘客,相较于第一次作业的FAFS算法,有了很明显的进步,性能大大提高,难度也有所提高。输入输出接口仍然给好了jar文件,无需我们担心。下面先看一下IDEA对于我代码的分析。

类图

方法复杂度

复杂度较高的几个方法中都包含了较多的if条件判断,为确保正确性,只能以性能换正确。代码设计并不是十分到位。

类复杂度

第二次作业,我按照指导书使用了ALS算法,每到一个楼层,我会先让进程sleep(400),以度过开关门时间,然后检测电梯的等待队列中,是否有当前楼层的乘客在等待,若有则进入电梯乘客队列,接着遍历电梯乘客队列,将到达楼层为当前楼层的乘客送出电梯,每一次电梯运动前,都会更新一下当前的目标楼层,目标楼层也会综合考虑等待队列中的出发楼层,然后电梯根据目标楼层选择向上运动或向下运动,每运动一层为一个周期。

我认为这次作业的难点也就主要在调度一块,若是调度算法太差会导致Real-Time-Limited-Exceed,若是暴力轮询不sleep()会出现CPU-Time-Limited-Exceed,这也是我后面自己试出的一个小技巧,由于对于wait(),notify()两个方法的理解不到位,我的电梯内部采用暴力轮询,以防止错过任何一条指令或是进程在等待i队列还有指令的时候就结束。 但是我在获取指令的进程中采用了notify(),以唤醒get()方法中的wait()。

第二次作业我并不是十分成功,由于个人架构太失败,导致调度环节出问题,电梯运行方向并不会正确的改变,导致在强测时挂了多组数据,未能进入互测,这次作业我吸取了教训,知道一个不正确的架构,一定写不出一个正确的程序,在开始码代码前一定要考虑周全,想到程序运行的每一方面,尤其是结束进程方面,一定要在开始之初就设置好信号量,做好规划,而不能等到写完程序后在程序内部打补丁,强行结束程序。

第三次作业——三部电梯(自行调度)论述

第三次作业提高要求,设置为三部电梯,且每台电梯能够到达楼层互不相同,也就导致了需要乘坐两台电梯才能到达目标楼层的操作,且每台电梯运行速度,最大承载量也不相同,一开始我想使用继承,一个父类电梯包括电梯所有操作,然后用子类修改电梯的各种数据,造出三台电梯,但后来我发现了更加直接的方法,使用构造方法来确定电梯的几个参数,无需使用继承,且继承run方法我也不太确定是如何运行的。下面先看下IDEA的分析。

性能分析

类图

方法复杂度

复杂度高的函数如Tray.get(),因为三台电梯不同,导致获取的目标也不同,也就是用了if判断语句,增加了复杂度,但以后可以使用数组,传入index以减少if的使用,而在获取aimFloor一块,依然复杂度极高,毕竟有多种情况,我只能使用if判断,手动判断情况。

类复杂度

第三次作业我还是使用了生产者-消费者模式,由于会出现一台电梯无法送达的情况,我选择在当初将指令放入等待队列时,便拆分好,我会考虑所有的中转楼层,选取其中路线最短的中转楼层,然后将前一条指令先放入恰当的电梯中,后一条指令放在我的Monitor线程中,这是我新开的一个监视者线程,负责查看出电梯人员中,是否有id与监视者的等待队列中的id相同,若有,则该等待队列中的指令放入适当的电梯等待队列中,其他的架构都与第二次作业都差不多。

第三次作业的强侧表现也不太好,在这里我分享一下我debug的经历,我频繁出现CPU-Time-Limited-Exceed的问题,根据以往的经验判断,一定是暴力轮询没有sleep导致的,但我也并不是很清楚是哪一个while循环出现的暴力轮询,于是我才用输出debug的方法,在每一个while循环内部都都增加了输出,“XXX(类名):XXX(方法名) Here!”, 以判断哪一个while出现暴力轮询,当然输出结果极其恐怖,一个txt文件里面有25w+行的输出,显然找到了bug所在,但是自己在课下测试时并没有仔细测试。

这一次的经历也教会了我使用JProfiler,可以在Thread模块,查看是否有block,若是出现block,即代码内容有问题,然后使用输出debug,找到bug所在。

同时,在研讨课上,也有同学分享了System.error方法,可以输出错误数据,以后debug时可以尝试。

OO第二单元——多线程(电梯)的更多相关文章

  1. OO第二单元多线程电梯总结

    OO第二单元多线程电梯总结 第一次作业 设计思路 Input为输入线程,负责不断读取请求并将读到的请求放入调度器中. Dispatcher为调度器,是Input线程和Elevator线程的共享对象,采 ...

  2. OO第二单元多线程电梯总结分析

    一.概述 这一部分的作业考察的关注点与上一次的作业有所不同,上一次的考察重点主要集中在输入输出的判定以及多态的考察上面,而这一次是让我们进行多线程程序的调度与开发.这次开发过程中最大的感受就是自己之前 ...

  3. BUAAOO第二单元多线程电梯作业总结

    第二单元多线程作业需要保证线程安全

  4. oo第二单元——多线程魔鬼电梯

    在初步认识了面向对象思想后,立刻进入了多线程的学习,本单元的难点主要是锁的理解,需要保证线程安全的同时防止死锁的发生,也要尽可能缩小锁的范围,提高性能.这一单元以电梯为载体,让我们从生活出发,从电梯运 ...

  5. OO随笔之纠结的第二单元——多线程电梯

    综述 主要任务就是写一个电梯模拟器,读入每一个人的请求然后让电梯把他们送到想去的地方. 从第一次到第三次作业,三次的主要任务都是相同的,但是每次都增加了很多的细节,每次的难度都逐步增长,电梯复杂度和瞎 ...

  6. OO第二单元总结——电梯调度问题

    一.设计策略. 在三次作业中,多线程程序的实现分以下几个步骤: 1. 主线程Main类的创建多个线程. 2. 共享对象的synchronized锁保证线程之间的互斥访问. 3. 采用notifyAll ...

  7. OO第二单元总结——电梯

    在电梯系列的作业中,笔者的整体架构几乎没有发生改变.现介绍如下,对于一个电梯系统,主要的工作步骤就是获取乘客请求.分派请求.执行请求.针对这样的工作模式,笔者设计了Elevator.Uselist两个 ...

  8. 电梯也能无为而治——oo第二单元作业总结

    oo第二单元作业总结 一.设计策略与质量分析 第一次作业 设计策略 在第一次作业之前,我首先确定了生产者--消费者模式的大体架构,即由输入线程(可与主线程合并)充当生产者,电梯线程充当消费者,二者不直 ...

  9. oo第二单元作业总结

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

随机推荐

  1. python库--tensorflow--数学函数

    官方API(需FQ) 中文API 方法 返回值类型 参数 说明 算数运算符 .add() Tensor x, y, name=N 加法(若x,y都为tensor, 数据类型需一致, 以下所有x,y都如 ...

  2. urllib库爬虫技术从0开学习

    urllib库 urllib库是pytho中一个最基本网络请求库.可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据. urllopen函数 在python的urllib库中 ...

  3. [源码解析] 深度学习分布式训练框架 horovod (21) --- 之如何恢复训练

    [源码解析] 深度学习分布式训练框架 horovod (21) --- 之如何恢复训练 目录 [源码解析] 深度学习分布式训练框架 horovod (21) --- 之如何恢复训练 0x00 摘要 0 ...

  4. 简单入门PHP中的多字节字符串操作

    什么是多字节的字符串操作呢?其实不少的同学可能都已经使用过了,但我们还是要从最基础的问题说起. 一个字符占几个字节并不是我们表面上看到的那样.正常情况下,一个数字或英文以及英文符号都是占用一个字节的. ...

  5. trait能力在PHP中的使用

    相信大家对trait已经不陌生了,早在5.4时,trait就已经出现在了PHP的新特性中.当然,本身trait也是特性的意思,但这个特性的主要能力就是为了代码的复用. 我们都知道,PHP是现代化的面向 ...

  6. 分布式文件系统FastDFS在CentOS7上的安装及与Springboot的整合

    1. 概述 FastDFS 是目前比较流行的分布式文件系统,可以很容易的实现横向扩展.动态扩容.灾备.高可用和负载均衡. FastDFS 的服务分为 tracker 服务 和 storage 服务,  ...

  7. P7470-[NOI Online 2021 提高组]岛屿探险【Trie,CDQ分治】

    正题 题目链接:https://www.luogu.com.cn/problem/P7470 题目大意 给出\(n\)个二元组\((a,b)\). \(q\)次询问给出\((l,r,c,d)\)表示询 ...

  8. 深入浅出WPF-05.控件与布局

    控件与布局 突出特点:1.专门的UI设计语言XAML,无需像MFC那样使用编程语言设计UI.2.前几代在UI和数据交互方面是由消息Message到控件事件,始终是把UI控件放在主导位置而把数据放在了次 ...

  9. Winform配置文件读写操作

    前言 在项目当中为了增加软件的灵活性及可配置性,配置文件在程序当中起着不可替代的作用.下面介绍一下最近用的比较多的方式. config文件的操作 数据库连接字符串 1.获取连接字符串 public s ...

  10. 三千字介绍Redis主从+哨兵+集群

    一.Redis持久化策略 1.RDB 每隔几分钟或者一段时间会将redis内存中的数据全量的写入到一个文件中去. 优点: 因为他是每隔一段时间的全量备份,代表了每个时间段的数据.所以适合做冷备份. R ...