---恢复内容开始---

Homework1 傻瓜电梯

程序架构

第一次题目非常简单,思考也非常简单,一部电梯傻瓜调度。将命令入公共的队列,电梯从公共队列中取命令即可,其中只需要使用ArrayBlockingQueue就可以使线程安全,并不需要加上锁,因为只有这个队列需要公共访问修改,使用阻塞队列即可。

同步控制

第一次作业结构简单,只需要使用ArrayBlockingQueue就可以实现同步控制。

BUG的出现

1.使用电梯取队列命令时,若也使用阻塞取,就可能使整个线程阻塞而无法退出,因此我是用poll进行取。

2.程序退出不能仅仅判定输入为NULL,还得注意命令队列是否为空,不然将导致命令还没执行完就退出。

Homework2 捎带电梯

程序架构

这一次作业对电梯的架构做了很大的调整。它与第一次是完全不同的,因为第一次过于傻瓜,其实整个电梯类并不是电梯,而是一个运算器,对from和to两个floor进行运算时间即可,本质上并不是电梯。

所以首先我得明确什么是捎带,什么是电梯,捎带就是电梯仍然就是这么去接人,只不过接人的路上可能可以捎带上别人,它的接人方向和放人方向始终没有任何变化,因此我就将电梯的属性做了很大的调整,楼层的概念变得没那么重要,而方向作为主要属性,接人方向,放人方向和接人的极限层(即从接人任务结束的那一层)作为电梯每次开始运作的基础,然后每一层再给它分配任务,而不对这三个属性做任何变化。

比起第一次的傻瓜电梯,多加了一个调度器类,同时将请求队列放在了调度器中(调度器并不是一个线程,只是一个普通类,在电梯要调用时调用)。电梯多了outelelist和inelelist两个数组,用于存储在电梯外等候的人和在电梯里的人。电梯以pick和put为一次流程,每一次流程给电梯设置pick的方向和put的方向,以及pick的楼层,然后电梯开始运行,每当运行到一个楼层(初始层也算),就给电梯分配可以捎带的任务并且加入到电梯的outelelist,并且检索outelelist是否有可以进入电梯的,有就加入inelelist(等于人进电梯),并检索inelellist检索是否有达到楼层的,有就从inelellist移除(等于人出电梯),这些操作就完成了这一层的任务,并继续运行直到pick和put结束。

同步控制

虽然第二次设计复杂了很多,但是其实被线程共享的数据只有主请求队列,而电梯内部的两个接人放人数组都是私有的,只为电梯线程使用,因此不需要控制,所以我主请求队列仍然使用阻塞队列即可。

BUG的出现

1.起初我数组遍历使用下标从小到大进行遍历并且检索到就用数组的remove,这就会导致当我remove一个元素之后使size变化而下标i继续增长,某些元素无法检索到,解决办法就是从大到小遍历。

2.在调度器每次给电梯设置pickdirection时,将正确的direction传递给电梯,然而调度器内部记录的direction没有变化,导致会增加一些不能经过的捎带任务,从而使电梯不断爬楼却无法到达捎带楼层而无限爬楼。

Homework3 捎带电梯+多部不同的电梯

程序架构

复杂度控制还行

电梯类

电梯和调度器的时序图

类的数量并没有变化,依然是电梯类,调度器类,输入类,和主类。电梯完全可以复用,只要设置上升下降速度,载客量,可停靠楼层,开关门时间就可以将多部电梯一样操作。

多部电梯和任务的关系是竞争关系,电梯去竞争任务而不是靠调度器调度任务,对调度器加锁,每次只有一部电梯可以进行调度,其他电梯就得等待。

对于载客量的限制,只要调度器每次判定电梯的总任务数量是否超过载客量(包括电梯内的和电梯外的),只要超过就不派发。

对于楼层问题,直达楼层就如作业二一样,并没有任何变化。而对于不直达楼层,我们需要对其进行分割,将其分成两个可以直达的任务,即分割第一任务和分割第二任务,这就需要解决以下几个任务:1.何时分割。我在Input类就进行了分割操作,一输入并不马上加入任务队列,而是先进行分割操作。2.如何保证先做完分割出的第一任务,再执行第二任务(即先送到中转楼层,再去接他到目的楼层,不然会造成去接但是人还没到的情况),因此我在调度器中加入了waitqueue和wastequeue,waitqueue存储的就是分割出来的第二任务,而wastequeue是电梯inelelist中被remove的元素。每次调用调度器,就检索整个wastequeue,查找其中是否有和waitqueue中相同的id(因为中转的是同一个人),有就把waitqueue中的请求加入主请求队列等待电梯竞争,没有就找下一个,并且把wastequeue的元素都清空。这样就可以保证时间的先后性,但是多次的循环检索可能会造成计算时间过长。

同步控制

新增的waitqueue和wastequeue都为多线程共享,因此我将其都调用线程安全类,使用ArrayBlockingQueue和ConcurrentHashMap两个类,保证其线程安全,同时在使用调度器的代码块加上锁,从而保证每次只有一部电梯调用调度器。这样就完成了整个同步控制流程。

BUG的出现

这次最严重的bug就是时间问题,CPU常常超出所规定的时间,原本我采用第二次作业的版式,只在电梯类的最后加入一条sleep()指令来完成暂时的休眠,然而第三次作业的调度器类太过于臃肿,其中循环检索太多使CPU运行时间过长,所以我就在每次调用调度器就notifyall并wait,并且在调度器内部也穿插了sleep,然而这就会导致另一个问题,当另外两个电梯结束线程后,就会使最后一个电梯永远停留在wait状态,于是我就使用wait(time),当wait超过time的时间就自动唤醒,从而解决了一个电梯运行的无限等待问题。

查找BUG策略

对于自身BUG查找,使用print法,在每次线程调度的开头和结尾都使用print,并且使用部分模拟数据来测试。

对于查找他人BUG,并没有很好的办法。

三次作业总结

这三次作业,让我对于多线程编程有了更加深刻的认识。它和单线程有着很大的差别,对我们的编程能力有着很大的考验,这就需要我们严谨的架构能力和对线程安全的重视。 我的架构能力确实有所提升,第二三次作业都是使用同一个架构。然而我对同步控制仍然还有很大缺陷和漏洞,我仅仅使用简单的线程安全类和一把锁,锁的范围过大也导致了某部分代码块需要运行过久时间,对notify和wait的使用也仍然生疏,这还需要多加练习。

BUAAOO第二单元总结之电梯问题的更多相关文章

  1. OO第二单元——多线程(电梯)

    OO第二单元--多线程(电梯) 综述 第二单元的三次联系作业都写电梯,要求逐步提高,对于多线程的掌握也进一步加深.本次作业全部都给出了输入输出文件,也就避免了正则表达式判断输入输出是否合法的问题. 第 ...

  2. BUAAOO第二单元多线程电梯作业总结

    第二单元多线程作业需要保证线程安全

  3. 2019年北航OO第二单元(多线程电梯任务)总结

    一.三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程.这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以 ...

  4. OO第二单元作业——魔鬼电梯

    简介 本单元作业分为三次 第一次作业:第一次作业要实现单部简单电梯,停靠所有楼层,无载客容量,性能分考量电梯运行时间. 第二次作业: 第二次作业实现多部电梯,电梯数量由初始化设定,每部电梯都停靠所有楼 ...

  5. BUAA-OO第二单元小结

    一.设计策略 三次作业中,由于前两次作业都只有一部电梯,因此我的线程只有两个,一个等待队列输入进程,以及一个电梯运行进程.等待队列输入进程实现十分简单,只需要根据输入把request添加到等待队列即可 ...

  6. BUAAOO第二单元代码分析

    第一次作业 设计思路与感想 第一次作业是要求有捎带的电梯实现, 第一次作业是花费的时间比较长的一次,花费了很多的时间去思考架构的问题.起初是想要搞三个线程的:输入线程,调度器线程和电梯线程,想要搞一个 ...

  7. oo第二单元——多线程魔鬼电梯

    在初步认识了面向对象思想后,立刻进入了多线程的学习,本单元的难点主要是锁的理解,需要保证线程安全的同时防止死锁的发生,也要尽可能缩小锁的范围,提高性能.这一单元以电梯为载体,让我们从生活出发,从电梯运 ...

  8. OO第二单元总结——多线程电梯

    第五次作业分析 1.设计策略 调度器采用单例模式,内部设请求队列,对请求队列的一切操作(查.增.删)都在调度器内完成,且都要求串行,从而确保线程安全.接收器和电梯是两个线程:接收器接受请求调用调度器来 ...

  9. 第二单元电梯调度作业 By Wazaki

    figure:first-child { margin-top: -20px; } #write ol, #write ul { position: relative; } img { max-wid ...

随机推荐

  1. C# DataGridView 动态添加列和调整列顺序

    https://yq.aliyun.com/articles/421700 // DataGridView1的ColumnDisplayIndexChanged事件处理方法private void D ...

  2. python2 与 python3的区别

    python2 与 python3的区别 几乎所有的python2程序都需要一些修改才能正常的运行在python3的环境下.为了简化这个转换过程,Python3自带了一个2to3的实用脚本.这个脚本会 ...

  3. python程序—名片管理系统

    创建一个名片管理系统,实现增.删.改.查.四项功能 listcard = [] while True: print('**********欢迎来到名片管理系统**********') print(' ...

  4. Unity日常记录-本地保存未来时间实现倒计时

    本地保存未来时间实现倒计时 TimeTool工具类:获取当前时间.未来时间.两时间差 using System; using UnityEngine; public class TimeTool { ...

  5. Openstack中keystone与外部LDAP Server的集成

    openstack中keystone鉴权的用户user和password信息,通常保存在mysql数据库的keystone库: 表local_user和表password: keystone也支持外部 ...

  6. centos7安装python,mariaDB,django,nginx

    0,安装centos7 centos默认不开启网卡,需要在安装时将ens33设置为on,或者后续通过vi ifcfg-ens33,找到onboot,设置为yes ssg登陆centos7时,如果提示W ...

  7. DPDK kni创建要先于port开启

    DPDK kni创建要先于port开启 1. DPDK kni创建使用API:- rte_kni_init- rte_kni_alloc 2. DPDK port开启使用API:- rte_eth_d ...

  8. 【HDU - 1429】胜利大逃亡(续) (高级搜索)【状态压缩+BFS】

    Ignatius再次被魔王抓走了(搞不懂他咋这么讨魔王喜欢)…… 这次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了带锁的门,钥匙藏在地牢另外的某些地方.刚开 ...

  9. hadoop 安装之 hadoop、hive环境配置

    总结了一下hadoop的大致安装过程,按照master . slave的hadoop主从类别,以及root和hadoop集群用户两种角色,以职责图的方式展现,更加清晰一些

  10. Lucene配置环境变量

    更详细的内容请参考:http://www.cnblogs.com/itcsl/p/6804954.html 以下是参照上面的操作方式来说明的,首先下载lucene-6.2.1.zip文件,这个网上有的 ...