(1)从多线程的协同和同步控制方面,分析和总结自己三次作业来的设计策略及其变化。


第五次作业

  第五次作业是对多线程的初步探索,所以对于多线程的基本书写机制的认识比较多。本次作业难点在于了解多线程的运作机制,努力构建线程安全的操作方式,合理构造电梯之间、电梯与请求之间的协作关系。值得注意的是电梯、乘客在问题域中具有并发行为:

(1)电梯之间“竞争”响应请求:也即电梯共用一个请求队列,电梯之间对请求的处理不得重复、也不得有遗漏,这对于线程安全的要求是很高的

(2)乘客之间“竞争”使用电梯:满足捎带策略的电梯使得满足乘客需求并不是那么简单,他要求电梯根据自己的需要适当的捎带顺路的乘客。这就造成了两个问题:如何保持乘客请求队列的完整性和独立性?如何为不同的电梯选择个性化的捎带目标,同时在宏观上又对电梯有统一的调度策略?调度器(线程)如何知道电梯(线程)的状态?

  首先,关于保持乘客请求队列完整和独立的问题也就是线程安全的问题,只有线程安全处理的好才能不重不漏的取走乘客的需求,这里我们通常使用三种同步策略:线程代码加锁和中间过程on-demand加锁和共享对象加锁,经过长期的摸索,最简单易懂也不容易出错的方案是对共享对象加锁,也就是对托盘加锁。使用关键字对托盘的访问、修改方法进行锁定。这意味着共享对象不可以过于庞大,否则使用加锁的方法可能会使线程变得卡顿,时间误差拉大。同时生产者-消费者模型是必须掌握的多线程间交互模式。

  其次,关于多线程电梯捎带的个性化和统一性,我采用了和PPT上一样的设计方案,如下图所示。也即1大+3小的设计模式,大队列用于储存所有的合法请求,小队列用于放置调度器给电梯个性化选择的待处理请求。值得注意的是,三电梯的捎带和单电梯的捎带在调度器设计上有明显区别。而FR则需要一套更复杂的判断机制。比如设计重复请求函数,条件是当某个电梯处于服务状态且请求方向和目标楼层和该待判断请求一致时,该请求被判定为重复请求,应该从大队列中删除不予分配,这是很多同学容易忽略的细节。ER的判断相对简单,类似的设计只需要判断对应的电梯。调度器的策略为循环扫描大队列,将满足分配条件的请求分配到电梯,不满足的保留。保留策略是这次作业调度器设计的重点之一。

  多线程交互中的共享对象设置一个status board,电梯线程把自己的状态发布到board,调度器从中读取电梯状态。其中的get set方法是本次作业的坑点,线程不安全通常是某个线程错误读取了另一个线程未来得及修改的共享信息。修正方法是尽量把修改和访问操作整体化封装,尽量避免多线程锁的争夺强度加大,在争夺轮替间隙错误读取信息。

第六次作业

  第六次作业的重点仍然是多线程,这里主要是对文件系统的构造和操作必须熟悉,文件操作线程安全类的封装要完备可靠,文件和目录最好是分开创建,另一个重点是快照的建立也即递归多叉树,以及基于快照的比较逻辑,这里更加推荐一个监视对象一个线程的做法,我采用的是一种监视器一个线程然后里面有监视队列,但这样因为监视器的相似性代码冗余比较多,而且监视器之间的区别也容易被搞乱,写起来效率不高。同时当文件发生移动时,修改也比较麻烦。记录本质上是一种同步行为,触发控制线程独立输出到一个内存对象(buffer),然后集中输出到外存文件的做法效率更高一些。

  这次与众不同的是我们开始接触编写代码来进行测试:程序输入不是都通过显式的命令行或控制行而是通过打靶式测试——有目的的设计输入,这样效果预计性和可复现性变得很强。

  和前几次作业的平稳落地不同,这次作业因为各种改线程逻辑,框架变来变去,最后写的非常爆炸,debug到凌晨3点也没有挽救手残的程序员写出的糟糕作品,抱着必死的信念和下次一定好好写的自我安慰交了上去,最后连各种奇怪的debug输出也没删干净,没想到遇到了好心的周国杰大佬,帮忙给de了一波bug(感动.jpg)才不至于死的太过于惨烈,让我感到了同学情!!特此表示感谢!这也提示我们,框架一旦确定好,一定要有十足的把握认为框架的确存在巨大漏洞再考虑推倒重写,不要在几种类似的方案中摇摆不定,这山望着那山高,其实是在浪费时间,很可能不慎获得一次意想不到的熬夜机会。

第七次作业

第七次作业是一次新的系列作业,继续实践线程安全设计,对交互关系的分析尤为重要。

这是我在需求分析中的部分分析:

(1)乘客交互的数据特征:

乘客->调度器:请求位置、目标位置、系统获取请求发出的时间

调度器->乘客:是否有车响应等反馈

(2)乘客交互的时间特征:

乘客->调度器:有乘客请求会被移交到调度器,调度器只要发现立即处理

调度器->乘客:3秒时间一到派单,并及时给出反馈

(3)出租车交互的数据特征:

出租车->调度器:出租车的状态信息,包括车辆编号、当前状态、所在位置等,便于调度器判断出租车是否可用

调度器->出租车:分配订单,告知出租车有新单,浮动信任值

(4)出租车交互的时间特征:

出租车->调度器:每200ms做出一次移动,并随即向共享对象更新一次状态信息

调度器->出租车:抢单窗口关闭后进行派单,派单后立即告知相应出租车的共享对象有新单

MakeMap:负责读入文件、创建地图、创建邻接矩阵、计算最短距离

CarInformation:记录出租车信息和接单请求信息的共享对象

Input_Handler:处理输入的线程,将合法输入放入到请求队列中去

Request_List: 共享对象请求队列

Taxi:出租车运营接客等

  因为出租车之间有较强的独立性和严格的时间特征所以设计为一个出租车对应一个线程,出租车群体具有并发特征,并发行为有:检测接单、接单状态(以最短路径行走)、服务状态(以最短路径行走)、停止状态、等待状态(随意走动)。

  因为调度器可以模拟出租车调度平台所以将调度器设计为一个线程,扫描请求队列依次按时加车、派单并负责给用户反馈。

  设计一个输入线程,用于即时处理发出的请求并添加到请求队列。

另外hashmap是一个很好的key-value存储工具,强推。


(2) 基于度量来分析自己的程序结构


第五次作业

缺点:1、if else ,switch case 等判断语句会增加圈复杂度,导致代码复杂,不方便维护。

以后写代码按照制定的代码规范来,同时避免写 if,for 多层嵌套的代码,否则圈复杂度和块复杂度都会变得很高。

2、有些方法的参数数目比较多,说明对数据的管理分配存在巨大的优化空间,必须减少God类的出现也要注意数据传递冗余。

第六次作业

缺点:这次作业不仅没有把目录完成的特别好,而且因为初次接触文件的功能性内容,对触发器的设计圈复杂度和块复杂度都很大,是因为算法太繁琐嵌套太多所致。

第七次作业

缺点:可以发现这次作业check方法的问题尤为突出,是因为在这个方法中,一次性对所有的读入进行阶段性解析判断合法性处理,if else 和switch非常多,下次作业一定要思考如何简化合法性判断。

这几次作业的优点是代码量在努力减少,方法封装也用的越来越好,但进步空间还很大。


(3)分析自己程序的bug


第五次:1、程序不能自己停止,因为第一次使用多线程,线程之间的结束先后逻辑关系设计存在漏洞,导致当输入END时如果调度器大队列不为空或大队列不为空而小队列为空时个别线程在特定情形下无法结束。互测结束后已经对应程序进行了相应修改。

2、split使用错误:一定要记住这个神坑的特例;;;;;;;;,应该使用split(“;”,-1),同时注意对空分割的判断。

3、输出时间多了0.1s:多线程运行需要时间,会有一定的时间误差,可以选用假时间或sleep(本来标准的睡眠时长-程序运行至此消耗的时长)

第六次:监控目录存在一系列BUG,原因是递归建立快照的写法存在BUG,对递归的学习必须加强。作业的功能不全,以后有时间要继续研究。

第七次:吸取第五次作业的教训改用了假时间,没有被发现功能性BUG,但因为仓促写了文件读入,忘记判断创建地图的返回值,导致错误地图读入不能结束程序。


(4)分析自己发现别人程序bug所采用的策略


  前两次作业的BUG树比较细致,基本功能的测试都是依照BUG树去构造的,特殊边角的测试主要针对代码的特点,有选择的去读一些自己认为易错的地方的代码,比如快照对比、快照建立、电梯调度器的设计逻辑等,最后一次作业主要是记住自己写程序的时候认为容易忽略的地方比如出租车系统出租车状态机中关于停止的设计、关于调度器抢单的设计逻辑、以及有意攻破线程安全的一些方案,有意制造矛盾点,使得线程交互设计的弱点暴露,同时对于时间的掐算也要有自己的一套判断标准。


(5)心得体会


  经过三次多线程工程模式的训练,我从对JAVA多线程陌生到能根据JAVA代码的运行特点去修正线程安全问题实在经历了太多挑战的辛酸,但正是这种坚持一下就看到胜利的终点的状态让我学会了很多。线程安全方面我学会了简化共享对象、共享对象的安全封装等,可以从一个设计者的角度去分析需求,分析哪些应该被设计为线程,哪些应该附带共享对象才能交互。线程安全方面需要有合理的访问机制,包括关键字和wait notify的正确使用。设计方面应该有归一思想,能简则简,尽量减少线程竞争,不变动的数据不要使用共享对象而是使用拷贝的方法等。在线程竞争不可避免时,设计合理的访问方案,尽量减少结果的不确定性,是我们永恒的追求。

  另外,写代码最好还是多和同学讨论,只要不触及代码层面都是有益无害的,多人讨论会有更多启发,也容易及时纠正思想误区,避免很多思维漏洞导致的BUG。尽量不要先写一个特别大的框架然后一点点细节去重新改,因为可能省略的地方太多最回头写完想打补丁都忘了,毕竟细节决定成败。

第5-7次OO作业总结分析的更多相关文章

  1. 前三次OO作业小结

    I used to be enamored of object-oriented programming. I'm now finding myself leaning toward believin ...

  2. oo作业总结(二)

    概述 和前三次作业相比,这几次作业最大的不同是难度的飞跃.遗憾的是在这难度的变化面前,我自己却没有做好充分的准备,错误的低估了作业难度导致给自己带来了很多不必要麻烦和损失.接下来我将对它们进行说明(度 ...

  3. oo作业总结(一)

    概述 经历了三次oo作业的洗礼,让我对java语言的强大以及面向对象编程有了初步的理解(当然,我是小白).本文接下来就将对自己这三次作业的代码进行分析以及分享自己的心路历程. 基础知识点考核 针对前三 ...

  4. oo作业总结报告

    oo第一次博客 以前从未真正的写过Java代码,接触Java也只是寒假的时候简单的看了看语法,不懂该如何面向对象,但没事,心里不惧,想着什么都是可以学的(直到真正开始写工程的时候,才发现自己还是太天真 ...

  5. 北航oo作业第一单元小结

    前言 在经过了三次艰辛的oo作业后,oo课程的第一单元告一段落,这一单元,我作为一个oo小白,开始了解oo的编程思想,也有了自己的一点心得体会.把笔粗成字,不当之处,还请各位大佬多多指教. 一.分析程 ...

  6. 北航oo作业第四单元小结

    1.总结本单元两次作业的架构设计 在我动手开始总结我的设计之前,我看了其他同学已经提交在班级群里的博客,不禁汗颜,我是真的偷懒.其他同学大多使用了新建一个类,用以储存每一个UMLelemet元素的具体 ...

  7. 大作业NABC分析结果

    大作业NABC分析结果 这次的大作业计划制作一款关于七巧板的游戏软件.关于编写的APP的NABC需求分析: N:需求 ,本款软件主要面向一些在校的大学生,他们在校空闲时间比较多,而且热衷于一些益智类游 ...

  8. oo作业总结(四)

    测试与正确性论证 测试是通过构造一系列测试数据,通过对比程序的实际运行结果和预期输出结果来判断程序是否有bug的一种手段.同时,在测试的时候是默认看不到程序的具体实现的,即进行黑盒测试,例如每次OO作 ...

  9. 【作业】HansBug的前三次OO作业分析与小结

    OO课程目前已经进行了三次的作业,容我在本文中做一点微小的工作. 第一次作业 第一次作业由于难度不大,所以笔者程序实际上写的也比较随意一些.(点击就送指导书~) 类图 程序的大致结构如下: 代码分析 ...

随机推荐

  1. python远程执行dos命令

    https://blog.csdn.net/huaihuaidexiao/article/details/5543240 https://blog.csdn.net/bcbobo21cn/articl ...

  2. 创建Oracle表空间

    *分为四步 */ /*第1步:创建临时表空间 */ create temporarytablespace user_temp tempfile 'D:\oracle\oradata\Oracle9i\ ...

  3. ajax请求中包含中文参数

    对需要传递的中文参数先进行两次转码: 1.js文件中使用encodeURI()方法. var url = "Validate.jsp?id=" + encodeURI(encode ...

  4. 比较C#中几种常见的复制字节数组方法的效率

    在日常编程过程中,我们可能经常需要Copy各种数组,一般来说有以下几种常见的方法:Array.Copy,IList<T>.Copy,BinaryReader.ReadBytes,Buffe ...

  5. V-REP与C++初步通信测试

    打开vrep,在上方操作栏找到help选项打开,选择help topics.此时浏览器打开了vrep的操作手册user manual. 在user manual左侧目录中找到writing code ...

  6. redis 配置文件解释 以及集群部署

    redis是一款开源的.高性能的键-值存储(key-value store),和memcached类似,redis常被称作是一款key-value内存存储系统或者内存数据库,同时由于它支持丰富的数据结 ...

  7. 如果测试UI

    1. 先分享几个链接 https://www.ranorex.com/resources/testing-wiki/gui-testing/ https://www.tutorialspoint.co ...

  8. hibernate的开始

    1.1对象的持久化 对象持久化是指将内存中的对象保存到可永久保存的存储设备中(如磁盘)的一种技术.(hibernate是通过id来管理对象) 1.2怎样实现持久化 1 对象序列化 2 JDBC 3 O ...

  9. js判断访问浏览器是安卓还是ios还是微信浏览器还是微博

    var u = navigator.userAgent, app = navigator.appVersion; var isAndroid = u.indexOf('Android') > - ...

  10. loading data into a table(亲测有效)

    一.实验要求 导入数据到数据库的表里    表内容如下: name owner species sex birth death Fluffy Harold cat f 1993-02-04   Cla ...