经过三周的自己电梯瞎设计,下次坐电梯想我想的可能就不是如何优化调度算法,而是千万别把自己死锁在电梯里了(手动狗头)

一、设计策略

1. 需求分析:
  • 作业一:单部多线程可稍带电梯,一部电梯,固定楼层,不限载人数,性能基准为ALS电梯
  • 作业二:多部多线程可捎带电梯,不定电梯数,固定楼层,限制载人数
  • 作业三:多部多线程可捎带电梯,动态增加电梯,楼层、运行时间、最大载人数为不同的固定值
2.设计分析:

终于体会到迭代的舒服之处了!!!

此三次作业基本一脉相承,始终坚持生产者-消费者模式要求,坚持WorkerThread模式要求,坚持多线程安全性最先的要求,成功的完成了迭代式的三次电梯作业。

一共四个线程,主线程用来启动输入线程和调度器线程,调度器线程中进行启动多部电梯线程,通过一个共享变量将输入线程和调度器线程联系起来构成生产者-消费者模式,调度器内部多个共享变量分别和各部电梯形成生产者-消费者模式。输入线程只管输入数据并将其放入主队列中,调度器线程只管将需求从主队列中取出并按一定的策略分配进各个电梯的外部需求队列中。电梯线程只管依据既定的稍带策略将外部需求队列中的请求取入内部队列中并完成既定运送。(在第三次作业中,由于有了换乘的存在,所以电梯还需要将out的需换乘的乘客重新放入主队列中,当做新的需求处理)

3. 调度策略

电梯自身的策略:LOOK算法,既简单而且效率还不错。(ps:由于自己第一次作业时魔改了一下LOOK算法,结果发现性能还不如纯LOOK算法性能高orz)

调度器策略:第一次作业,单部电梯,无需在此调度。第二次作业,经过多次魔改调度算法后对比发现,单纯的依据哪部电梯的队列需求最少最优的分配策略,性能更稳定并且更高,(优化点,可以采取手段让电梯自行争抢,而并不提前绑定电梯)。第三次作业,同样经过多次魔改调度之后发现,单纯依据各种类电梯的统一需求队列中的需求最少最优的方案,真的真的真的性能最高,同类型电梯共用一个需求队列,自行争抢,毕竟此次性能值包括了乘客总花费时间和电梯运行时间。

我真的不太明白,每次迭代之初修改调度算法时偷懒用的最少最优的调度,竟然比之后处心积虑修改的调度性能更高。难道这就是传说中的大道至简?

4. 死锁问题

很不幸,三次作业我都出现了死锁问题,但是又很幸运的是,这些问题在提交中测之前都发现了(笑脸.jpg)。原因分析为,我在多线程中采用的是synchronize块在需要时再锁对象的方法,随意经常导致锁的交叉需求问题,进而程序一直相互忙等状态。我采取的方法是,理论分析。列出所有有锁的地方,挨个分析互锁的可能性并进行修改。

5. 第三次作业的可扩展性分析

输入线程部分只需根据输入进行解析扩展即可,调度器线程只需根据电梯的要求扩展变化和代替共享的队列以及修改调度算法即可(调度算法虽未单独抽象为一个类,但是已被简化为一个函数,故修改应该也方便),电梯可根据要求修改固有属性即可。

二、SOLID分析

SPR--单一职责原则:软件组件(函数、类、模块)必须专注于单一的任务(只有单一的职责)

我的输入类,调度类和电梯类都只专注与输入,调度分配和电梯运行三个功能,所以我认为满足了此原则。

OCP--开/闭原则:对扩展开放,对修改关闭

由于调度类中的调度算法并没有抽象出一个类,所以在迭代时难免会对调度类产生修改。以及电梯的属性变化,也会使我直接修改源代码,所以此原则不太符合。

LSP--替换原则:子类型可以替代其对应的基类型

由于电梯都是统一建模通过构造参数来创建新的电梯,故本次作业并未涉及继承部分。

ISP--接口隔离原则:将大而全的接口拆分成特定的客户端接口

作业中并未用到接口。

DIP--依赖倒置原则:抽象不应该依赖于细节,细节应该依赖于抽象

电梯类由于是统一建模,具体细节由统一模型的构造参数决定,所以我觉得一定程序上符合此原则。

三、基于度量分析

第一次作业:

第二次作业

第三次作业:

(由于IDEA更新,metrics插件无法使用,故根据记忆以及手动得出以下分析)

三次作业中的run方法好像复杂度都有点高,应该是方法抽离不完全所致

其中第三次作业中Person类的复杂度尤其高,由于我在Person类中case打表进行决定是否换乘,故复杂度极高(争取以后能用算法解决的,我都能够不打表)

四、分析自己程序的bug

此三次作业中,强测和互测均为出现bug,结果归功于我的评测机和手动分析死锁情况,在中测结束之前找出了所有的问题。(由于第一部分已分析了死锁的问题,故在此不再赘述)

五、互测策略

此次多线程互测相比上一单元的互测来说,评测机要求更高,自己写定点投放程序,自己写逻辑判断程序。(ps:我的第一次评测机竟然连到达0层的bug都没测出来,tcl)

其次,由于过分的相信评测机,所以我基本采用的都是黑盒测试,极少手动构造样例,所以三次互测中基本没有收获(除了最后一次,有同学对X1X2X3以外的电梯名称报错,才找到了一个bug)

最后,多线程的独有特性,即使在自己的评测机上出错,在课程组的评测机上也不一定会错;当然自己评测机不会出错的例子,课程组的评测机上也不一定不会出错(当然我没遇到该种样例hhh)

六、心得体会

多线程的锁真的是一个艺术的东西,多了会把自己锁住,少了就会出现莫名其妙的错误,当然锁自己也是有可能的。多线程安全必须慎之又慎,以及多多动手理论分析一下,没有自己解不开的锁(如果有,那就砸烂换把锁)。

(总结起来就是,多线程的安全就是要么我锁我自己,要么就在玄学的世界里畅游,当然大佬都是掌控一切,恰到好处的放锁)

设计原则部分,由于在作业进行中,课上依次讲解了生产者--消费者模式和WorkerThread模式,所以这三次作业的总的框架展开,细节和具体实现通过自己的想法即可。

不得不说经过这三次作业的训练,我加深对多线程经常出现玄学bug和死锁的安全性问题的理解,以及对生产者--消费者和WorkerThread模式的掌握和熟练。实在是收获颇丰。

以及,自我测试和互测的时候一定要黑盒白盒一起上啊,不能偷懒.jpg。

OO_Unit2_Summary的更多相关文章

随机推荐

  1. WebAssembly JavaScript APIs

    WebAssembly JavaScript APIs https://developer.mozilla.org/en-US/docs/WebAssembly/Using_the_JavaScrip ...

  2. K8s炼气期(一)| minikube安装本地Kubenetes环境

    前言 根据Kubenetes学习路径的七大阶段,炼气期.筑基期.金丹期.元婴期.化神期.炼虚期.大乘期:开始炼气期的第一个小阶段,安装Kubenetes环境. 目录 1.安装kubectl 2.安装m ...

  3. CSS中Position属性static、absolute、fixed、relative

    在html中网页可以看成一个立体的空间,一个完整的页面是由很多个页面堆积形成的,如下图所示   CSS中Position属性有四个可选值,它们分别是:static.absolute.fixed.rel ...

  4. JVM基础入门

    内存模型 我理解的jvm: 个人理解的jvm流程: .java反编译为.class文件 经类加载器到上图的内存模型 方法区:存静态 常量区(String在里面) 本地栈区:调本地服务其它库的方法 计数 ...

  5. ThreadPoolExecutor中execute和submit的区别

    1:入参不同 excute() 传入的是 Runable, submit 传入的是 Callable 或 Runable 1):execute 方法源码 public void execute(Run ...

  6. docker08容器监控工具-WeaveScope

    容器监控工具WeaveScope 一 背景 在生成环境中k8s应用部署众多,需要一款可视化工具方便日常获知集群的实时状态,并为故障排查提供及时和准确的数据支持. weavescope支持docker和 ...

  7. WPF -- 一种圆形识别方案

    本文介绍一种圆形的识别方案. 识别流程 判断是否为封闭图形: 根据圆的方程,取输入点集中的1/6.3/6.5/6处的三个点,求得圆的方程,获取圆心及半径: 取点集中的部分点,计算点到圆心的距离与半径的 ...

  8. 使用pycallgraph分析python代码函数调用流程以及框架

    技术背景 在上一篇博客中,我们介绍了使用量子计算模拟器ProjectQ去生成一个随机数,也介绍了随机数的应用场景等.但是有些时候我们希望可以打开这里面实现的原理,去看看在产生随机数的过程中经历了哪些运 ...

  9. [Elementary Mechanics Using Python-02]Feather in tornado

    Problem 9.17 Feather in tornado. In this project you will learn to use Newton's laws and the force m ...

  10. 任务4 PHP扩展模块安装

    /usr/local/php/bin/php -m //如何查看PHP加载了哪些模块 #cd  /usr/local/src #wget http://pecl.php.net/get/redis-2 ...