OO第二单元 多线程电梯 总结回顾

写在前面

  这是笔者第一次接触到多线程编程,不会debug、编程时需要考虑的因素增加、很多bug难以复现,成为了我此次作业最大的障碍。编程时看着自己独具一格的电梯,默默下定决心要是我以后要是从事类似的工作,绝对不会乘坐自己开发的电梯。不过在这个单元里我确实有很大的收获,也能在乘坐电梯时自然地思考电梯的调度算法了。

一.设计策略

  本单元的三次作业都沿用了生产者-消费者模式。由于输入都较为简单,故输入直接在Main类里完成,而并未单独构造生产者线程。输入指令后,request作为产品,通过缓冲区的put()方法传入托盘(缓冲区),而电梯作为消费者,则通过get()方法从托盘里获取指令并运行。调度功能在缓冲区实现。在主线程里启动和结束电梯线程和缓冲区线程,其中,电梯线程的结束借助了一个结束信号end。在缓冲区,put和get方法需要保证线程安全,通过synchronized及wait、notifyAll实现。电梯每次循环都通过get从缓冲区中获取指令,如果当前无指令(或无需要当前电梯的指令)、电梯内无人、电梯无还未处理的请求、程序还未结束,则电梯进程进入wait状态。每当有新指令加入或程序输入结束,则notifyAll。

二.设计的可扩展性

  本单元的作业充分吸取了第一单元每次都重构的教训,在第一次作业时仔细思考了架构,在程序的扩展性方面有了很大的提升。三次电梯都沿用LOOK算法,单电梯的运行除了因题目要求更改了乘客上限和运行楼层时间外,三次作业所有种类的电梯都采用同一个建模。生产者(即主类)线程几乎未做改变。其中调度器改变较大。1、3、5、15层为固定换乘楼层,如某条指令需要换乘,则将该指令的transfer属性赋为true,并且将TO楼层换为1、3、5、15中的一个,并且新增一个指令(即该指令到达楼层后的换乘指令),当该指令到达换乘楼层后调用get方法将指令加入缓冲区。

  在第三次作业里,由于ABC三个种类的电梯采用了同一种建模,因此指令的分派完全由调度器完成,这样使得电梯的功能较为专一。当一条指令put到缓冲区以后,会根据From和To楼层判断是否需要换乘、接受该指令的电梯,并为其附上相应的状态,这样的操作极大的提高了可扩展性。

SOLID原则:

SRP:

  这三次作业都较为简单,一共有五个类,主类MainClass负责启动和结束其他线程并完成输入,电梯类从调度器获取指令后运行并输出,调度器类作为缓冲区,在主类输入指令后,对指令进行分析,为指令标上需要换乘的电梯及是否需要换乘,并且提供get方法供电梯类调用。people类在requset类的基础上,增加了transfer属性来描述是否需要换乘,People保存换乘后的属性,elevator属性表示该指令需要乘坐的电梯,以及设置from楼层和to楼层的方法。safeoutput类确保输入的线程安全。五个类的职能明确。

OCP:

  电梯线程一直未做太大的改变,但是调度器线程三次迭代一直在修改。其余部分未使用继承。

LSP、ISP、DIP: 

  除了Thread外,三次作业均为使用继承和接口。

三.基于度量的分析:

第五次作业:

UML图

 

代码行数

耦合度分析

   

  

时序图

  第五次作业采用生产者-消费者模式,总体构造不复杂,一共三个类。电梯采用LOOK算法,缓冲区提供put和get方法,同时使用synchronized保证线程的安全性。从耦合度来看,电梯LOOK算法的实现写的很繁琐。

 

第六次作业

UML图

代码行数

耦合度分析

      

时序图

  第六次作业沿用第五次作业的设计,同样是三个进程。电梯进程几乎未改动,依旧是LOOK算法,电梯之间的调度采用随机分配。电题LOOK算法的实现依旧很繁琐。

 

第七次作业

UML

代码行数

耦合度分析

          

时序图

  第七次作业依旧沿用了生产者-消费者模式,单个电梯依旧以LOOK算法运行,电梯类除了循环条件和人数上限、运行时间外,未做其他改动。1、3、5、15层为固定换乘楼层。调度器负责为指令分派电梯,同时提供Put和get方法。可以看到由于未对电梯线程做改动,电梯线程的耦合度依旧居高不下。同时由于重写了request类,使得时序图复杂了许多。

 

四.分析自己程序的Bug

  第五次作业强测和互测均未出现bug。

  第六次作业强测未出现bug,互测被hack一次。由于粗心,只有一个电梯时超载时可能会使电梯线程提前结束。

  第七次作业强测和互测均未出现bug。

  三次作业里,自己debug时问题都出现在电梯run方法的while循环判断条件上和电梯wait循环的判断条件上,在刚开始写代码时总会出现电梯线程未能结束的情况。在这些方面浪费了很多时间。

 

五.分析自己发现别人程序bug所采用的策略

  总体采用交自己测试时想到的特殊样例 + 肉眼看代码的模式来debug。

  第五次、第六次屋子有同学使用了sleep,故使用间隔超长时间的指令(第一条和第二条指令的输入时间间隔50s)hack成功。

  第七次在看代码时发现一位同学对新增电梯的电梯编号理解错误,hack成功。

 

六.心得体会

  本单元的作业感觉难度攀升不大。第五次作业时刚接触多线程编程,上手花了很长时间。另外两次作业均在第一次作业上做了很少的改动即可通过测试。所花的时间比第一单元少了很多(虽然是因为我对性能没有太高的追求)。但经过三次作业,突然发现随机分配竟然也能拥有如此好的性能,第七次作业刚开始加了很多优化性能的操作,最后发现还不如最开始的纯随机分配,还多了产生很多bug的风险,最后还是删了。虽然多线程debug对我来说是真的很迷。。但运气很好没遇到麻烦的bug。

  第七次作业的心路历程很崩溃。中测刚提交时最后两个点出现了ctle,花了几个小时认认真真的又看了几遍代码,花了各种手段测试,结果刷新了一下网站竟然通过了。互测时惊奇地发现自己被hack了,隔了两个小时hack又消失。

  第一次接触多线程,虽然很艰难但有很大的收获。OO课程已过半,希望接下来能顺利~加油加油!

  

  

 

猜你喜欢

转载自www.cnblogs.com/wtrwtr/p/12702634.html