我那十分不完美的编程经历(2)

又过去了一个月,OO课程的第二单元也告了一段落。

回想这第二个单元的课程目标,很明显可以抓住一个重点:多线程。

那么第一个问题来了。

Q1:什么是线程?多线程有什么用?

A1:这个问题在操作系统课程中也有很详细的讲解。通俗地来理解,一个线程可以被认为是被主程序(进程)指派去执行一个任务的“分身”。至于多线程的价值,我自己的理解不深,但是从实际应用角度来看,可以支持多个需要并行的任务。并且多线程可以有效地减少程序执行的时间。

Q2:我还是有点不理解,多线程的Java和单线程的C之间有什么不一致的地方呢?

A2:根据我自己的理解,单线程的C是主函数main一家独大的。整个程序都需要main函数去执行流程中的所有操作,“一手包办”所有的函数调用与数据维护。通俗地说,main函数很“勤快”,但是难免显得单打独斗。但是Java多线程程序中,main方法只是作为每一个线程的“启动器”,main方法本身很“懒”,它把自己的任务都交给了各个线程,“放养”它们并且让它们各干各的。这就相当于有一个监督者下的合作模式。

那么接下来就在实践过程中一起来理解多线程的奥妙。

 

第五次作业——多线程电梯

很不幸地,由于第四次作业中,电梯捎带算法的实现失败,直接导致了第五次作业没能完成。(嗯,这是我个人能力的锅,不过就算作业截止日期已经过去了,没有学会的东西还是要补上,不能让这个坑永久存在。)

不过我认为作业的难点其实不在于多线程具体代码的操作,重点在于基于运动量来分配电梯的任务。从现实生活看,这也是比较合理的,可以省却电梯空载运行带来的能量耗费。

Q3:我好像觉得有点不对劲……如果两个电梯抢单怎么办?在调度器获取电梯状态的时候,如果有一个电梯偷偷地改变了状态怎么办?

A3:这个问题嘛……我还没想好……能不能待会儿再说?

 

第六次作业——IFTTT文件监视器

刚刚拿到监视器这个任务的时候,第一反应就是做一个“即时的”监视器,只要文件一旦发生相应变化,就应该立刻反应。但是仔细思考之后,发现根本做不到。主要的问题在于,文件的变化无法告知监视器,必须要监视器来主动探查。而监视器对于文件状态的获取和判断可以认为是一个瞬时的过程。

所以监视器必须以一种固定的频率来扫描文件目录,同时对于文件状态进行感知,由多次的短时间间隔的刷新来近似达到实时更新的目标。

怀着这个目的,对于多线程设计就有了一个比较明确的指导了。每接到一个文件就创立一个新的线程,选择相应的任务进行监视,比对文件信息,若触发了相应的条件,则进行相应的操作。

本质上来说,这次作业对于设计方面并没有苛求太多。相应的扫描文件目录、获取文件信息、设置触发条件、执行操作等都可以封装在一个方法里,并且方法之间并没有相互之间的干扰。

难点应该是Java文件类和真实文件之间的关联,以及:如何做到线程之间不相互干扰,即线程安全。

我对于线程安全有一个模糊的印象,就是加上一个锁,每次只允许一个线程对于文件进行修改。但是,对于文件状态的获取,即“读”操作,则是不受限制的。因为读操作对于文件信息是没有更改的,也就是说以任意的顺序进行读操作的结果都是一样的。

Q4:所以我刚才的问题有头绪了么?

A4:稍微有点了。就是在每一个方法前加入一个锁,对于所要执行的操作进行限制,最后释放锁,相当于强制每一个线程进行一个“排队”操作。

一下是对于我的代码的一些分析:

(类图)

(分析图)

非常遗憾,我的作业交错了位置,放入了答疑的git仓库内,导致作业无效……

但是自己在进行测试的时候,发现了许多需要完善之处。

1.在测试的时候将线程数量限制修改为了1,但是没有改回来。

2.对于输出至文件的操作不够细致,没有进行封装。

3.没有提供测试接口。

4.在进行recover操作的时候,发现自己不能将文件放回原来的位置,而只能修改最后修改时间、文件大小和文件名等信息。

 

第七次作业——出租车叫车系统

本次作业第一次提供了GUI界面进行观察。(变得有趣了很多)然而,核心的问题仍然在于:如何避免出租车之间的抢单?

多线程的设计自不必说。我的设计是将100个出租车都作为单独运行的线程,而把调度器作为一个单独的线程。输入请求后,则会调用InputHandler类进行解读和判断合法性。如果合法,则添加到指令队列中。调度器每100ms扫描队列,如果时间没有到窗口关闭时间,则会收集可用的出租车信息。如果时间到且有车,则删除该订单,按照指导书中的要求,选择信用最高、最近的出租车。该出租车接到指令,改变为接客状态,以最短路径前往乘客处,再将乘客送往地点。若无车,则提示无车。除此之外,出租车都在自由运动。

(类图)

(分析)

可以发现,对Taxi类的分析中,run方法调用了极其冗长的方法。一个就是wander()方法,用来实现出租车的随机运动。但是每一次执行都要让出租车计算周围四个方向的连通性,非常慢。除此之外,其他的方法中还有一个前往目标点的算法,没有做好代码的复用。

互测:

测试我的同学没有发现我的bug。

我在测试的时候犯了乌龙。我的程序能够在console中直接输出错误信息,然而那位同学的是直接输出在文件中,我想当然,认为这是个bug。同学经过申诉后,我第一时间改正了错误,对那位同学要说声对不起。

此外,这次作业强调了设计的原则性。对此我还没有相应的深入了解,但是对于这个已经有了一些模糊的认识。

 

仍然希望我们共勉,争取提升自己的编程与设计水平,不要放弃,加油。

猜你喜欢

转载自www.cnblogs.com/gilbert-gorshkov/p/8981899.html