ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BUAAOO 第二单元

2021-04-26 02:05:16  阅读:208  来源: 互联网

标签:同步 队列 第二 作业 调度 电梯 线程 BUAAOO 单元


第二单元OO总结

Part1. 代码构思设计

 

 

 

  • 输入线程(input):只要有输入,便会交由调度器,增加电梯外等待队列。当输入停止后,输入线程直接结束。
  • 电梯线程(elevator):不断运转(即正常的接人送人操作),若电梯内外都没有人且输入停止,则电梯线程结束。
  • 调度器:

    HW5 :调度器内管理电梯队列和电梯外的等待队列,同时管理电梯移动的策略方法、在每层停留时电梯内外的队列增减人时的方法。

    HM6HM7 : 将本来由调度器管理的队列交由电梯自己管理,调度器只负责将输入线程传入的需求按照一定的策略分配给特定的电梯管理。每个电梯都有自己的等待队列和电梯内队列,并且配有管理电梯移动的策略方法,电梯如何移动完全交由电梯自己处理。

Part2. 同步块与锁

1. 同步块

  • 同步块:
    • 同步块设置意义:所有同步在一个对象上的同步块在同时只能被一个线程进入并执行操作。所有其他等待进入该同步块的线程将被阻塞,直到执行该同步块中的线程退出。

    • 同步块在作业中的应用:

      从part1的设计可以看出,我的构造内涉及到同步对象的只有两种情况:调度器分配请求给电梯,改变电梯的等待队列;电梯停留在某层,进行接人和送人时电梯队列的改变。

2. 锁

  • 同步控制机制
    1. monitor机制

    2. lock机制

  • 上锁原则:务必保证拿到同一把锁
  • 锁的类型:
    1. ReentrantLock:可随处使用

    2. ReentrantReadWriteLock:单写、多读

    3. Read Write Lock等

  • 我的选择:

    我在作业中采用新建一个锁类,并且生成static锁对象,用同一把锁锁住了所有的同步对象。因为加锁不当容易产生死锁,而且在本次作业中需要保护的共享对象仅有电梯等待队列,所以采用一把锁已经足够。同时采用copywriteArrayList这种线程安全的容器用来盛放队列,减少了需要加锁的地方。

3. 锁与同步块语句关系

  1. 方法一: 确定同步块内的共享对象,将其作为锁住的对象,即限制访问该对象的线程数量。

  2. 方法二: 直接新建锁类和锁对象,将代码区锁住,限制访问该代码区的线程数量(这也是我作业当中采用的方法)

Part3. 功能&性能设计

  • HW5

 

 

 

 

可以看到电梯线程和输入线程之间是通过调度器进行连接,输入线程添加调度器内等待队列的人数,电梯线程减少(通过运输)等待队列的人数。

  • HW6+HW7

 

 

在后两次作业中,调度器不再管理队列,只负责决定处理来自输入线程的请求到底应该分配给哪个具体的电梯。

额外的,正如下图所示,最后一次作业考虑到了换乘,所以调度器还负责处理标记乘客信息,如果需要换乘,那么置标记位为1。

 

 

  • 扩展性分析

    这次的作业我个人认为扩展性做到较好,每次代码改动量不超过100行,这也得益于清晰的结构划分和功能分配。

    模式采用生产者-消费者模式,所以明确生产者为输入线程,消费者为电梯线程,调度器只是中途容纳请求的容器(顺便将生产者的请求划分出来,分别给予不同的消费者)。

    同时,将电梯各个操作分别封装为方法,比如电梯的上下移动、乘客进出、电梯移动策略等。

    在之后的迭代中,第二次作业增加了电梯数量,这只需要设置添加几个消费者线程同时start即可。第三次作业增加了换乘和多类电梯,只需要修改电梯的特性和增加调度器对请求的处理操作(如标记是否换乘)即可。

Part4. 分析bug

  • HW5

    第一次强测挂了两个点,都是源自没写morning模式并且LOOK算法写错了,导致数据超时。自以为运行时间不会有太大差别,但没想到会直接tle。所以人还是尽量不要偷懒QAQ,多分析一下输出数据是不是预想的那样,而不是看到输出正确就草草了之。

  • HW6、HW7

    这两次作业强测都过了,只不过性能分有所差异。因为第一次作业做完后我就推迟了bug修复,直到第二次作业都截止了我才发现LOOK算法有问题,当然已经来不及了。第三次作业修改后性能分也提升了,总的来说,修复bug应该尽量提前,不然就是为后面的作业挖坑。

Part5. 分析别人bug策略

  • hm7

    这次作业是最容易产生bug的,因为很多人在实现换乘时往往会出错。所以不妨多多设置同一时间多个人到来,并且都需要换乘的数据。

Part6. 心得体会

  • 线程安全

    最开始接触线程安全时,总觉得难以下手,不知道何时让线程开始,如何让线程结束,在过程中如何加锁,如何设置wait和notify。通过这三次作业,我也有了一点小的心得。

    首先,线程的开始并不需要太介意什么时候开始,可以设置一个Init函数,固定进行start线程。

    其次,线程的结束取决于终点判定,在run方法内的while(true)设置好break的判定条件即可。

    synchronized (Lock.getLock()) {
                while (waitQueue.isEmpty() && inQueue.isEmpty()) {
                    if (exQueue.isEmpty() && Input.getEnd()) {
                        break;
                    }
                    Lock.getLock().wait();
                }
            }

     

    比如这段代码便是对电梯线程的结束判断,当输入关闭,内外队列都为0时,就可以直接break了。

    然后,在思考如何加锁时,首先确定共享对象是什么,哪些代码只能单个线程进入,划定好临界区。然后锁住共享对象或者自己设定的锁即可。

    最后,索取资源未有时,便需要wait,(不wait而是采取轮询的话,可能会导致cpu超时,但是听有的同学说巧妙的轮询比wait-notify优越很多)。当资源产生时(或者结束),便进行Notify。

  • 层次化设计

    这次清晰地体会到了层次化的重要性,将任务按照功能和特性不断细分,形成树状结构,对之后的迭代很有好处。

    比如这次的作业当中,让电梯管理自己的运动和队列,因为这都属于电梯自己的运动特性,应该交由电梯自己管理

  • 心路历程

    写电梯的难度较之表达式可以说是小了不少,因为顾及的细节少了很多。同时策略的选择也很重要,在遇到不懂的地方应该尽快搜索相关资料,而不是闭门造车。

标签:同步,队列,第二,作业,调度,电梯,线程,BUAAOO,单元
来源: https://www.cnblogs.com/zhuxixi/p/14702841.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有