第二单元的做业是面向多线程的电梯编程,经过这一单元的做业,笔者基本掌握了多线程编程的方法。算法
task:单部先来先服务调度电梯,用户请求能够在任意时刻到达。编程
设计策略:安全
虽然第一次做业仅仅只有一部电梯,可是须要一个专门的线程用于处理输入,与电梯线程并发执行。因为须要准备向多电梯扩展,我在此次做业设计时并无直接将输入给到电梯,而是通过了scheduler中转后,再由电梯得到而后执行。多线程
此次做业我总共设计了两个线程,InputHandler和Elevator,共享对象是Scheduler。InputHandler将处理好的请求放入Scheduler的队列,ELevator将请求从Scheduler中取出而后执行。架构
所以为了保证线程安全,须要对Scheduler的requests队列的操做作同步控制,具体体如今InputHandler向requests队列放入请求和Elevator从requests队列取请求时都须要先得到requests队列的锁。并发
至于两个线程之间的协同体如今1.requests队列为空时,电梯须要等待,我采用的是CPU轮询的方法。2.InputHandler线程结束后,Elevator线程须要知晓,w为此我在InputHandler中设置了一个hasInputFlag的变量,标志是否还有输出,电梯能够经过查询该标志变量来检查输入线程是否结束,以便决定自身线程是否结束。框架
优势:函数
缺点:单元测试
task:单部可捎带电梯实现,用户请求可随时到达。测试
设计策略:
本次设计较第一次有了较大的改变。因为调度器如今须要使用可捎带算法来为电梯分配请求,考虑到程序运行效率问题,调度器也能够做为一个单独线程与InputHandler和Elevator线程并发执行。
此次做业笔者总共设计了三个线程:InputHandler、Elevator和Scheduler。InputHandler与Scheduler的共享区包括requests队列和inputOver标志;Scheduler与Elevator的共享区包括requests队列和runOver标志。
为了保证线程安全,InputHandler对requests队列的放入操做与Scheduler对requests队列的取出操做都须要先申请锁;Scheduler将请求放入电梯的requests队列和电梯从本身的requests队列中取请求都须要先申请锁。
本次做业线程间的协做体如今:首先由InputHandler接收输入进行处理后放入Scheduler请求队列;而后Scheduler执行调度算法,将请求分配给电梯;最后电梯执行运行算法,完成请求。为了实现三个线程间的同步控制,每得到一个输入后,InputHandler对Scheduler进行notify;当requests队列为空时,Scheduler处于wait状态;Scheduler每分配一个请求后,对Elevator进行notify;Elevator的requests队列为空时,Elevator处于wait状态。这样既能够保证不浪费CPU时间,又可以保证各个线程及时被唤醒工做。
优势:
缺点:
task:三部运行参数不一样的电梯,使用可捎带调度算法,用户请求实时到达。
设计策略:
本次做为是多部电梯的运行,并且每部电梯的属性有所不一样。三部电梯之间是并发执行的。
此次做业笔者总共设计了5个线程:InputHandler、Elevator和Scheduler。InputHandler与Scheduler的共享区包括requests队列和inputOver标志;Scheduler与Elevator的共享区包括每部电梯的requests队列和runOver标志。
为了保证线程安全,InputHandler对requests队列的放入操做与Scheduler对requests队列的取出操做都须要先申请锁;Scheduler将请求放入电梯的requests队列和电梯从本身的requests队列中取请求都须要先申请锁。
本次做业线程间的协做体如今:首先由InputHandler接收输入进行处理后放入Scheduler请求队列;而后Scheduler执行调度算法,将请求分配给电梯;最后电梯执行运行算法,完成请求。为了实现5个线程间的同步控制,每得到一个输入后,InputHandler对Scheduler进行notify;当requests队列为空时,Scheduler处于wait状态;Scheduler分配完当前队列中全部请求后,对全部的Elevator进行notify;Elevator的requests队列为空时,Elevator处于wait状态。
此次做业还新增了换乘的功能,为了实现换乘,笔者的策略是在Scheduler中就首先拆分好,第一段交由电梯执行,第二段暂存在Scheduler的transfer队列中,当第一段被电梯执行完毕后,电梯通知调度器对第二段进行分配,这样就保证了第一段的永远先于第二段执行,实现了同步控制。而且因为transfer队列的存在,Scheduler线程结束的条件不只是输入结束和requests队列为空,还要算上transfer对列也为空才能结束线程,当全部请求分配完毕后,若transfer队列不空,Scheduler会进入wait状态,等待电梯通知。
优势:
缺点:
前三次做业在公测中都没有出现bug,因为未参加互测,所以没有进一步发现bug。
多线程编程最重要的一点就在于线程安全的处理,凡是涉及到了线程共享的部分都须要进行加锁操做。这里就须要咱们找到到底哪些地方出现了共享,一般共享出如今参数传递、返回值、引用变量赋值这些地方,对于多线程编程中的这些场景咱们必定要格外注意,对于出现了共享对象,要追踪其全部使用位置,检查操做是否安全,不然一旦出现不可控的安全问题,靠debug来查找问题来源是极为困难的。
除了多线程编程外,这一单元笔者同时还接触到了设计原则。SOLID五大经典原则能够说是在实际开发过程当中应该随时恪守的,从需求分析到架构设计到代码实现,每一步都要注意设计原则,并且在实现完成后还要进行设计原则的检查,在不当的地方进行重构以符合设计原则。不少同窗可能很讨厌这种工做,认为又麻烦有没有意义,可是笔者认为在实际的软件开发过程当中,遵照设计原则是极其重要的。如今因为做业规模小,并且迭代开发次数少,不遵循设计原则看起来影响不大,一旦到了社会上,软件的开发每每规模庞大并且要通过不少次的迭代开发。在这种状况下,若是没有一个统一的设计规范,一我的一套规则,那相互之间的合做就会变得无比困难,别人开发的软件你可能彻底无法读懂,更别谈进行迭代开发;即便你可以读懂,若是该产品通过屡次迭代后,有些类的安全性、独立性等都已经发生了改变,那么要想在已有基础上进行修改,就可能须要向后追溯到好久之前实现的代码上去进行阅读,白白浪费大量时间。
总的来讲,设计原则应该贯穿于整个软件开发的过程,遵照设计原则,能够帮助咱们更好的进行设计和开发。