第一次做业是先来先服务的"傻瓜电梯",我当时以为这个设计未免太简单了,因而就在傻瓜电梯的基础上加上贪心算法,每次都执行电梯内外距离最近的请求(可是没有行进中的捎带)。因为第一次没有限制CPU时间,并且个人wait--notify用得不太熟,所以就采起了暴力轮询的方式。我将我将调度器线程写在了main函数中(这是个很很差的设计,第三次做业中将其改进)做为一个线程,电梯做为一个线程,输入做为一个线程一共三个线程。另外我设计了一个personlist的类以及一个person类,这个类里面有一个属性是flag,flag表示这我的的状态,我规定了三种状态(0:未上电梯1:在电梯内2:在电梯外),这样我就不须要对personlist作remove操做,只须要每次都遍历personlist看它里面全部person对象的状态便可,人上下电梯也就变成了对flag的更改。其中输入线程阻塞式输入,每次输入以后转换为一个person对象加入到personlist中,而后电梯线程不断的轮询:判断是否开门—>开关门—>寻找下一个最近的楼层—>去最近的楼层。在开关门阶段电梯只负责开关门,人上下电梯由调度器负责,电梯开关门是将开关门标志位置为true,而后电梯sleep,这时调度器线程控制人的上下,当输入线程结束后,调度器线程就会不断判断是否personlist中的全部人的flag均为2,若是是并且电梯线程的门是否已关标志位置true,则调度器线程结束,电梯线程我设置为守护线程,在调度器线程和输入线程都结束后它也会平稳结束。python
第二次做业是同向请求可捎带的“ALS电梯”。个人线程设置和上次相同,有两点改变。第一,为了限制CPU时间避免暴力轮询,我使用了wait--notify让线程在不需运行的时候wait,这是就须要多线程的协同与通讯。在输入线程每输入进来一次请求时,都会notifyAll一次,这时会唤醒电梯线程(我是采用标志位置true+notifyAll来实现唤醒特定线程的),在输入线程结束后会唤醒调度器线程看是否须要结束程序。在电梯线程中,每次开关门时要唤醒调度器线程让它负责人员上下,每次关门要唤醒调度器看程序是否能够结束。第二,在电梯运行过程当中每到一层都会判断是否有同向可稍带请求,若是有的话就执行捎带,若是没有的话继续运行便可。算法
多电梯是一个很复杂的问题,个人思想就是化繁为简,ABC电梯被我设置成了三部ALS电梯,三个线程。每一个电梯有一个调度器,也是三个线程。这样一共六个线程,电梯的三个线程为守护线程。只要一个电梯可以执行的请求我就会让一个电梯来执行,遇到了一个电梯执行不了的请求,我会设置一个固定的楼层让它换乘,这些工做在电梯读入请求前就作好了,这样每一个电梯只管本身能够接的请求,就至关于三个ALS的结合,感受也是我对"请求调度与请求实现分离"的理解。编程
本文采用MetricsReloaded插件进行复杂度分析,其中OCavg表明类的方法的平均循环复杂度,WMC表明类的方法的总循环复杂度。设计模式
本文采用IDEA内置diagram生成类图。安全
优缺点分析:我新建了一个person类去存请求(就至关于人),personlist是请求的一个队列,有三个线程。优势是实现简单,把电梯选请求都放到电梯线程中易于编码;缺点是该分离的功能没有分离实现,调度请求本应该是调度器的功能却交给了电梯去实现。多线程
因为没有继承和接口,所以对于LSP,ISP,DIP法则暂不考虑。架构
对于SRP,每一个类都有一个明确的职责。这个完成的不太好,个人电梯类既进行了运行电梯,又进行了选择请求(至关于调度),应该让每一个类的功能明确且单一。并发
对于OCP,感受实现的还能够,以后的两次做业均可以套用这个架构,电梯的运行机制基本不变,须要改变的只是调度的机制和扩充为三部电梯,符合“无需修改已有实现,经过扩充来添加新功能”。函数
优缺点分析:优势是实现简单,把电梯选请求都放到电梯线程中易于编码,还有一点就是我把全部的输出写成了一个Output类,体现了面向对象封装的思想;缺点是该分离的功能没有分离实现,调度请求本应该是调度器的功能却交给了电梯去实现。性能
因为没有继承和接口,所以对于LSP,ISP,DIP法则暂不考虑。
对于SRP,每一个类都有一个明确的职责。这个完成的不太好,个人电梯类既进行了运行电梯,又进行了选择请求(至关于调度),应该让每一个类的功能明确且单一。
对于OCP,感受实现的还能够,第三次做业就至关于三部这样的电梯,电梯的运行机制基本不变,ALS调度也不须改变,符合“无需修改已有实现,经过扩充来添加新功能”。
优缺点分析:优势是实现简单,把电梯选请求都放到电梯线程中易于编码;把全部的输出写成了一个Output类,体现了面向对象封装的思想;请求调度与请求执行分离,每一个调度器和电梯至关于一个第二次做业,三个这样的系统就组成了此次做业,各种之间耦合度小,正确度高不宜出错。缺点是该分离的功能没有分离实现,调度请求本应该是调度器的功能却交给了电梯去实现;三个电梯和三个调度器本能够致谢两个类而我却在想保证正确性和性能想法的驱动下写了6个类。
因为没有继承和接口,所以对于LSP,ISP,DIP法则暂不考虑。
对于SRP,每一个类都有一个明确的职责。这个完成的还能够,虽然电梯类既进行了运行电梯,又进行了选择请求(至关于调度),可是每一个电梯和对应的调度器的这样的小系统是功能很是单一的,系统之间耦合度低。
对于OCP,完成的很差,调度方法基本没有什么扩展能力,电梯越多复杂度越高,可扩展性低。
因为我这三次做业的hack次数和被hack次数均为0,所以就来谈谈测试吧。多线程程序因为它程序执行结果的不肯定性以及程序bug的难以复现性,再使用手动输入测试的方法显然不合时宜。这时咱们就须要利用一些自动化的测试方式来测试咱们的程序。主要的步骤是
1)使用python开启一个子进程,启动待测程序
2)经过sleep完成定时输入,和第一步骤中开启的子进程通讯
3)检测输出是否符合要求
这三次做业处于对正确性的追求,我一直在用synchronize加锁,而在实现唤醒特定线程时我使用的方法是,设置特定线程标志为true而后notifyAll.然而,实际上彻底能够用功能更为强大的Lock和实现了Lock接口的可重入锁ReentrantLock.Lock比synchronize的优点主要体如今三个方面:
1)可让等待的锁响应中断
2)能够知道是否成功得到锁
3)能够提升多个线程进行读操做的效率
ReentrantLock+Condition能够更加优美的实现唤醒特定的线程。
为了提升程序的执行效率,咱们经常采起多个线程并发执行的方式。然而多线程中线程执行时序的不肯定性会致使线程不安全的事情存在。常见的read-then-write,check-then-modify模式的代码都会形成线程的不安全。那么在多线程编程中咱们如何能够尽量地保证线程安全呢?有如下几点值得注意的地方:
1)使用不可变对象,用final强制限制对属性成员的修改
2)保证操做的原子性:使用Atomic***类型变量
3)保证更改的及时可见:violate关键字的使用
4)读写访问的互斥控制:对须要同步的代码块加锁
总结起来,要想保证你的设计是线程安全的,这里有三个要素:
1)严格控制对象的发布与共享
2)将共享对象设计为线程安全类
3)线程类要保持简介
这三次做业我用到了面向对象的一些设计模式,还有我本身的一些设计原则
1)若是全局只存在一个对象(好比调度器),则采用单例模式构造调度器对象
2)若是一个对象的状态发生改变,须要另一些依赖它的对象收到通知并自动更新,则可使用观察者模式
3)Worker Thread模式也是一种很好的设计模式,应用于咱们本次电梯做业可将请求调度与请求实现分离
4)实现简单,架构清晰,正确度要比性能分更重要
时光飞逝,转眼间已通过去6次OO做业了,咱们本学期的OO征程也已通过半,这两个月以来,虽然很是的辛苦,可是的的确确收获了不少,虽然本身还有不少不足,可是对本学期OO的前半部分仍是比较满意的,但愿本身不断努力,继续加油!