一、多线程的设计
这三次作业的主要内容就是使用多线程并且解决多线程中出现的问题。而对于多线程我也有了自己的理解。首先明确的一点是单个CPU在同一时间只能处理一件事。那么,不管是多进程还是多线程,我们的CPU只是在其中不停地交换执行,只不过时间太短以至于用户感觉不到,这就是宏观上的并行,微观上的并行。我们的程序在启动的时候就会创建一个主线程,而我们可以在其中继续创建线程来完成我们的任务。
这样交替执行会带来线程不安全的问题。这样的情况有很多,常见的状态就是在A线程执行一个对共享资源的操作中,被B进程打断(CPU去执行了B进程),但此时,A进程的操作并没有结束,应该改变的某些值还没有改变,那么此时执行的B进程在对共享资源操作的时候必然会出现错误。
但是,多进程的使用是必然的,否则一些程序并没有任何实际价值。于是,有多种方法可以帮助我们实现代码的同步。Synchronized修饰符可以保证其内部的代码块是同步执行的,这个方法也是这三次作业中主要用到的方法。另外还有加锁机制和唤醒机制。
二、策略与设计
1)第五次作业:三部电梯的多线程设计
调度器的任务就是预先判断和分装。在电梯中执行的时候是以每一层为粒度,到一层后扫描一遍当前电梯的队列,执行在这一层的请求。主要涉及的线程是主线程,调度器线程和三个电梯线程。共享资源的冲突点在与三个共享队列在不同线程之间被访问时候的线程安全问题。于是,队列采用了vector类。扫描器使用的是timer。
2)第六次作业:ifttt文件监控
每一个监控任务有一个成员变量是当前的snapshot(原snapshot)在每隔一定时间后,进行新的snapshot的生成,与原来的snapshot进行比较,如果满足监控作业的要求,则输出。主要的问题在与写文件时候,因此采用每隔5s扫描一次的timer策略来完成。另外,此次作业采用了TestThread线程控制的测试方法,通过程序直接控制文件系统。
3)第七次作业 100辆出租车的调度
有主线程,扫描线程和调度器线程。通过设置成员变量的累计方式,控制单个出租车的状态。
三、度量分析
1)第五次作业:三部电梯的多线程设计
度量结果和前两次电梯作业的有一定的相似之处,因为调度器有继承,这一点可以从类图上看出来。新的调度器在重写的command_new方法上出现了超出标准的控制流和循环。其次,在电梯类中的remsame方法中,也是有很多控制流和循环。这个方法主要是用于判断并移除同质请求的,因为没有设置为方法,在程序中出现了三次,且判断过程也比较复杂,造成了电梯类内部冗余。
2)第六次作业:ifttt文件监控
主要的问题出现在比较快照的comp方法。在此方法中,需要比较四个监控作业的条件是否满足,需要比较的前提也都比较多,而且对detail.txt文件的输入才在这个方法中。其次就是在建立快照的run方法中,因为要实现将结果写入summary.txt文件中,需要控制流的参与。至于ele类的参数过多这一点是服务于detail.txt文件的输出。
3)第七次作业:100辆出租车的调度
主要问题在pathlength方法中,此方法是用bfs来计算两点之间的最短距离,对四个方向的遍历需要较多的控制流,且打印路径的操作放在了此方法中,通过一个标志变量控制。
四、bug分析
1)在三部电梯的调度中,出现了一个较大的问题,我尝试了与前两次不同的实现方法,结果考虑不够周全,用错了一个变量,使计算时间的时候产生了累积效应,在电梯类的模拟运动方法中导致时间的计算有错误,于是影响到了程序对到达楼层时间的预判,是一个很大的失误。
2)在文件监控中,没有仔细注意重命名和文件路径移动时需要判断是否是新产生的文件,否则就会导致我删除一个文件却触发了重命名等监控器。
3)设计原则问题,在表示状态的时候用隐含信息的数字表示。
五、发现bug的策略
1)从小处着手,测试基本的功能。
2)造成公共资源的竞争情况,通过观察输出之间的逻辑关系,看是否有矛盾,不合理的情况。
3)大数据的压力测试
六、心得体会
经历了这几次作业,对线程安全问题的解决停留在同步各个方法的基础层面上,这样操作使得程序运行慢,有些失去了多线程的优势。应该尝试着缩小同步代码块的范围,提高多线程的效率。
对于有些设计原则的理解还比较浅薄,但是设计原则确实很考验程序员的功底。对于程序来说,仅仅实现功能是不够的,遵循设计原则可以很好地提高代码的复用性和可维护性。以后在设计时需要考虑这些原则,完成一个好的设计。