OO第二单元总结

BUAA_OO_2022_第二单元总结

OO第二单元作业主题为多线程,具体的任务是要实现一个五栋楼的电梯系统,三次作业分别为每栋楼一个电梯,每栋楼多个竖向电梯且引入横向电梯,支持换乘且电梯参数可自定义,下面我分享一下我在本单元的学习心得和作业完成情况。

第一次作业

同步块的设置以及锁的选择

在整个第二单元中,我为了尽可能做到线程安全均使用了HashMap作为容器,在往HashMap中添加Object的时候就不用在外面设置同步块了,但要注意的一点是,在遍历HashMap的时候一定要将其写在同步块内,例如下面的代码块:

synchronized(hashmapToTraverse) {
    for(Object object : hashmapToTraverse) {
        // TODO
    }
}

同时,在整个第二单元中,我引入了两个Object实例:obj和outputLock,obj的作用是所为wait和notify的对象实例,具体用法的一个例子如下:

synchronized(obj) {
    // put something in the hashmap or we get null from stdin
    obj.notifyAll();
}

// if there is no request
synchronized(obj) {
    obj.wait();
}

而outputLock则是对输出加锁,避免输出时间戳不递增的情况。

调度器设计

由于第一次作业不涉及楼层间的互动,同时一个楼层也只有一个电梯,因此无需设置调度器。

整体结构分析及架构设计体验

第一次作业整体来说比较简单,难点主要是对于多线程和生产者消费者模型的初步理解。第一次作业需要关注的点在于电梯的调度,我采用的是sstf调度,即电梯每到一层,便会遍历电梯内外所有请求,找出离当前楼层最近的请求,然后往请求方向移动一层或者开关门接送乘客。sstf调度的优点是程序实际执行的realTime期望较小,但缺点是realTime方差较大,身边就有同学因为使用sstf而导致强测出现了RTLE的情况。

测试及debug

本次作业我强测挂了一半的点,因为我偷懒把电梯设置成开关门期间只许进出一名乘客,因为本来电梯开关门一次就可以完成的任务,我的电梯最多要开关门12次,这必然会导致RTLE。

在互测环节,由于我在B房,所以当我拿评测机跑其他同学的代码的时候,几乎所有人都出现了线程不安全的问题,最后我也是成功刀中了十几人次,为烂掉的强测回了一些血。同时,由于我的程序本身不存在调度和线程安全问题,我在互测中没有被hack。

第二次作业

本次作业和hw2一样,相对于上一次作业添加的内容都很大,但由于本次作业不涉及换乘,因此难度个人任务不像hw2相比hw1跨度那么大。

同步块的设置以及锁的选择

本次作业相比于第一次作业,我对于每个请求的处理和遍历都加上了同步锁,因为可能存在一个请求被两个电梯抢上,从而出现一个人进入两个电梯的情况,具体实现如下面的代码块所示:

synchronized(hashmapToTraverse) {
    for(Object object : hashmapToTraverse) {
        synchronized(object) {
            // TODO
        }
    }
}

synchronized(request) {
    // change the status of request
}

调度器设计

在第二次作业中,我对于需求的调度采取的是自由竞争策略,即“谁抢到就算谁的”,因此我没有单独开一个调度器类去调度所有请求。

整体结构分析及架构设计体验

本次作业相比第一次作业我进行了两部分的修改,一是将sstf调度修改成了look调度,二是添加了横向电梯,对于横向电梯,我依然是采用的look调度,但由于其是环形设计,我对look调度进行了微调,即:移动方向上两座楼内没有需求就使得电梯移动方向转变。同时,我也解决了第一次作业电梯开关门一次只能进出一个人的问题。

测试及debug

本次作业我是比较幸运的,在ddl前十分钟发现了程序中的一个线程不安全的bug并及时修改提交,使得我在互测及强测中没有被发现bug,不过事后我使用没修改的版本交强测也AC了。在互测中,我针对超载测试了几个数据点,可惜最后没有hack到任何一名同学。

第三次作业

本次作业中需要我们支持电梯的换乘,同时电梯的各项参数可以自定义。

同步块的设置以及锁的选择

在本次作业中,我并没有引入新的同步块,与第二次作业的同步块和同步锁保持一致。

调度器设计

在本次作业中,我对于需求的调度采取的依然是自由竞争策略,因此我依然没有单独开一个调度器类去调度所有请求,但本次作业需要我们实现换乘,我的实现方法是在请求被输入进来程序的时候,就根据横向电梯的情况把它拆成1-3个子请求,这里涉及到了换乘楼层的选择,我与官方策略的换乘楼层选择一致,即所有可以同时停靠请求起点和终点楼座的横向电梯中,离请求起点和终点距离之和最小的横向电梯的楼层为换乘楼层。

整体结构分析及架构设计体验

可以看到,本次作业我的主要修改就是增加了横向电梯信息类和子请求类,本质上这两个类都是为了请求拆分所服务的,因此电梯运行的调度我几乎没有进行修改。

电梯单元协作图

首先要指出,我在三次作业中整体架构是保持不变的,因此三次作业的协作图的整体框架基本是一样的,这里放出第三次作业的协作图供大家阅读:

测试及debug

在互测中,我针对请求拆分构造数据hack到了一名同学。

然后就是arrive的输出逻辑问题导致强测爆炸,第一次体会到C房的恐怖...

实在是...难 以 评 价

心得体会

在本单元的学习中我初步体会了多线程编程的思想,初步体会了多线程的生产者消费者模型。

本单元我做的比较好的地方是对于线程安全的处理,在本单元三次作业中没有一次作业产生了线程安全问题。而我做的不好的地方,甚至可以说是致命的地方只有一个字:懒。仔细想想,第一次和第三次作业寄强测或多或少就是因为懒。同时,第二次和第三次作业中我也没有去使用调取器去优化电梯的调度,不过身边很多人用调度器导致了性能分不升反降

可以说,oo最难的两个单元已经过去,接下来的三四单元可能难度会稍微简单一点,但是也依然不能掉以轻心,还是要有问题多提问,防止这次单元的“悲剧”在接下来的时间里反复重演。

posted @ 2022-05-04 15:47  hdd1211  阅读(32)  评论(0编辑  收藏  举报