OO第二单元多线程电梯作业总结

前言

  第二单元的作业主题是多线程电梯作业,在这个单元我们主要学习java程序的多线程编写,学会了如何创建线程,以及多线程之间的交互方法——生产者消费者模式还有在此基础上扩展的Worker-Thread模式和在这些模式中,wait,sleep,notifyall等方法的使用。在多线程交互的过程中,共享变量是十分关键的,而如何实现线程同步,确保其线程安全就成了一个非常重要的问题。所以我们又学习了如何使用synchronized关键字和Java类自带的锁来实现线程同步。

1.设计策略

  1.1第一次作业

  说句实话在看完吴际老师的第一次关于多线程编程的视频后,我整个人是处于懵逼状态的。如果说完全没听懂那倒还不至于,但整节课下来只是对多线程并发和交互有了一个大概的了解,如果说在这种情况下要让我独自上手完成第一次电梯作业的话,可以说是头发掉完也写不出来。幸好在第一次实验和指导书中介绍了生产者消费者这种多线程交互的模式,这让第一次作业的思路瞬间就清晰了。

  ·首先乘坐电梯的人作为生产者单独一个线程,其中的run方法不停的生产request,然后存入我们的缓存区——电梯调度器中。

  ·电梯作为我们的消费者单独一个线程,其中的run方法不停的从调度器中取得request请求同时进行楼层间的移动完成请求。

  ·电梯调度器作为缓存区(也是电梯和乘客两个线程的共享变量),其中有一个ArrayList来存放请求,并且实现了向ArrayList中put和get请求的方法。

  这个设计最为巧妙的就是电梯调度器了,其get方法会在队列为空时调用wait方法让电梯阻塞,put方法最后会在最后调用notifyall方法来唤醒之前被阻塞的电梯,而这两个方法都被加上了synchronized锁保证了线程同步。

  1.2第二次作业 & 第三次作业

  可以说归功于生产者消费者这个模式,让我在第二次作业中几乎只改动些许代码就顺利通过了。整体的架构几乎没有变动,唯一的区别可能就是电梯线程数的不同,但这丝毫没有影响,1-1和1-n对于生产者消费者模式来说几乎一样。至于电梯属性的不同,可以直接在电梯类中进行修改,对于整体架构也没有影响。

2.可扩展性分析

  2.1功能性分析

  前文提到了生产者消费者模式,可以说这个模式完美契合了电梯作业的各种功能要求。这三次作业的功能需求其实都没有什么太大的变化,第一二次作业从功能上讲几乎一样,而第三次作业的电梯由于种类的不同可停靠楼层有限制,导致了换乘的出现。而应对这个新增的功能需求,我的解决办法是选择不同电梯都可以停靠的楼层作为换乘楼层,在换乘楼层将需要换乘的乘客送出去,并调用电梯调度其中的put方法向请求队列中再新增一个新的请求,这样就实现了换乘的功能。

  2.2性能性分析

  这几次作业我其实都没有怎么去追求性能,但是最后取得的成绩其实还不错都是90+。

  ·第一次作业我的电梯调度算法选择的是LOOK算法并且在后面几次的电梯作业中都运用了LOOK算法,不是因为性能好还是其他什么原因,仅仅是觉得这个算法比较符合我们日常生活中电梯的行为逻辑,并且在程序的实现方面也比较简单。

  ·第二次作业有多部电梯,按理来说要追求性能的话应该在调度器中实现调度算法来合理安排多部电梯的行为,从而达到比较好的性能。但是自己苦思了一下午,苦于调度算法的编写困难,最后还是选择了无为而治。。。但是出乎意料的是第二次强测竟然得到了三次作业中最高的98分。。。后来我思考了一下得到这个结果的原因——大概是因为第二次作业的多部电梯在属性上并无任何差别,所以说可以认为他们的等价的几部电梯,那么在调度上就不应该有差别,对于不同的请求让他们各自去抢,谁先到就是谁的。这样的无为而治可能比一些不太好的调度算法表现的性能更优。

  ·第三次作业我继续顺延了第二次的无为而治,当然我知道这一次的效果肯定没有上一次好,因为不同的电梯有了不同的运行速度,在这种情况下有调度的安排电梯会更好。

3.度量分析

  3.1第一次作业

  

   

   

   第一次作业整体还是比较简洁明了的,可能其中稍微复杂一点的就是调度器中的get方法了。由于我向其中传入了3个参数,使其变得复杂。

  3.2第二次作业

  

   

   

   可以看出第二次和第一次的变化很小,比较复杂的还是get方法,因为在其中会遍历整个请求队列来取走符合要求的请求。另一个标红的方法是move,原因是我的电梯在每次move一层楼后会判断是否反向,这里进行的if判断较多。

  3.3第三次作业

   

   

   

   第三次作业可以明显看出复杂度变高了,原因就是增加了换乘操作我的hasTrans的换乘判断方法是通过遍历来实现的,导致其复杂度很高。而同时我是在人out电梯时进行了换成判断并新增了请求,所以该方法复杂度也变高了。

 4.自己程序的BUG

  在第三次作业编写的过程中我因为判断电梯线程的结束条件的不合理导致有些电梯过早的死掉,最后留下一个载有换乘需求的乘客电梯一直在运行但却无法完成任务,导致RTLE。然后在第二次互测中我因为判断让电梯进入wait状态的条件不合理导致所有电梯都会wait而无人唤醒被一位同学hack了RTLE。

 5.别人程序的BUG

  实话我在互测阶段的确偷懒了,一次互测数据都没有上交,不过实在是因为太菜了,不会编写评测机,而手搓数据去hack别人所花的精力太大,取得的效果也不会太好,所以最后就放弃互测阶段了。

 6.心得体会

  这个单元多线程编程其实挺难的,但归功于生产者消费者模式,为我们在完成作业时的代码架构方面省了不少力,多线程中最困难的线程交互,wait和notifyall的配合以及保证线程安全的synchronized锁和obj锁的运用都在这个模式中实现了。导致我这一个单元下来其实并没有对多线程中关键的方法有什么调用,在这么多行代码中,自己写的大部分是一些调度算法与多线程其实关系不大。当然这也并不只有坏处,起码我知道了这些各种各样的模式他们设计的精妙,通过学习这些模式,我们可以在一个全新的领域,快速上手编程并学习相关方法的使用和一些技巧,这也很不错。

猜你喜欢

转载自www.cnblogs.com/Lazyangel628/p/12727492.html