OO第二单元总结

OO第二单元电梯总结

架构模式

Hw5, Hw6, Hw7三次作业架构基本没有巨大变化,属于增量的叠加开发

hw5 一级生产者消费者模型with策略类分离

OO第二单元总结

第一次作业, 我做了两种架构的尝试, 写了:

OO第二单元总结
2. 带调度器线程的两级托盘

OO第二单元总结

在尝试写了两种架构的基础上, 我分析了一下两种架构,

  1. 不对任何数据进行区分, 所有数据对电梯可见
  2. 是二级生产者消费者模型, 仅仅对每个楼进行划分,每栋楼之间的请求隔离, 楼内请求电梯间是互通的

在我的两种架构里, 第二种架构的 scheduler线程仅仅负责取总托盘的请求,然后按楼区分发。本质上和你电梯直接去查找大托盘, 各取所需, 在功能上似乎没有任何区别。 反而调度祭天,减少了一个线程, 首先会简单不少, 其次, 每个电梯可见所有请求, 或许扩展性反而更好, 所以最终我选择了1作为三次作业的基本架构。

总之,对于架构的选择取舍就是:

要获取高效简洁解决问题的架构, 就得在调度自由度和懒癌(bushi, 简单度之间做取舍
​ ————沃兹基朔德

OO第二单元总结
关于策略类的提取:

​ 体现了DIP依赖倒置原则高级模块不应该依赖低级模块,而是 依赖抽象接口,通过抽象接口使用对应的低级模块

关于优化实现了:
  1. 量子电梯, 通过记录上次arrive & close 时间, 减少了wait以后,再被唤醒,可以快速的度过本层(其实就是拿一部分沉睡时间当作运动中的时间)比如:
    private void moveArrive() {
        try {

            Thread.sleep(max(400 + (lastArriveTime - System.currentTimeMillis()), 0));
            // Thread.sleep(400);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        building = (building + dir + 5) % 5;
        // arrive
        MyOutput.println("ARRIVE-" + buildingNameList[building] + "-" +
                floor + "-" + elevatorId);
    }
  1. 开关门400ms恒定保持
  2. 先下后上,尽量哆啦人(这不是共识吗?但我和其他童鞋交流时发现他没有,姑且算是吧

hw6 增加了两个电梯子类的一级生产者消费者模型

OO第二单元总结

这次作业中, 可以看到最令人神奇的就是:

  • 加入了横向电梯
  • 动态新增电梯
  • 不考虑换乘

这就意味着我们要为环形电梯设计新的的调度策略, 同时多个电梯这一次终于可以互相进行抢人, 这就带来了竞争和分配如何选择的问题

  1. 对于新增横竖电梯,还存在行为上的差异, 所以我搞了两个子类, 分别处理横竖方向的电梯
  2. 动态新增电梯, 这里其实暗示我们搞线程池, 然鹅我也现在才发现, 如果以后有机会可以搞个线程池, 其次由于选择了调度线程寄了天, 自然选择
  3. 提前为换乘打余量,我将托盘中的 PersonRequest 改成了 ConcurrentLinkedQueue<personrequest></personrequest>链表,具体怎么换乘hw7来说
  4. 环形电梯调度策略: 采用了类ALS基准策略, 效果还可以, 基本性能分都拿到了, 98+不戳的 Look也写了,但是担心出bug, 所以没有采取这个策略对象, 用了ALS, 当然Look肯定写好了是更快的

hw7 带换乘的一级生产者消费者模型

OO第二单元总结

可以看到基本没改什么, 就是在Input类中加入了一个换乘拆分函数

OO第二单元总结

线程的协作简图

OO第二单元总结

主要就是

  • 输入线程,接收到输出, 进行请求拆分, 或者创建电梯线程
  • 电梯线程, 在while循环中, 每次检测是否wait或者return, 此后决定上下人,并依据上下人开关门, 最后决定方向并前进

同步块和锁

总结分析三次作业中同步块的设置和锁的选择,并分析锁与同步快中处理语句之间的关系

三次作业架构基本保持了一致, 且同步块基本也保持了一致, 取最后一次作业的同步块讲解:

首先是 RequestTable.java中

// InputHandler 添加请求, Elevator送人到中转站时
public synchronized void addRequest(ConcurrentLinkedQueue a) {
        requests.add(a);
    }
// personLeft维护的是 没有送达目的地的人数
// InputHandler接收到请求时
    public synchronized void addPersonLeft() {
        this.notifyAll();
        personLeft++;
    }
// Elevator送人到目的地
    public synchronized void subPersonLeft() {
        personLeft--;
    }
// 输入结束
    public synchronized boolean isInputEnd() {
        return inputEnd;
    }
// 输入结束
    public synchronized void setInputEnd(boolean inputEnd) {
        this.notifyAll();
        this.inputEnd = inputEnd;
    }

// 上下是否没有请求了
    public synchronized boolean isUpDownEmpty(String buildingName) {
        ...

    }
// 同理
    public synchronized boolean isLeftRightEmpty(int floor) {
        ...

    }
// 前方是否有请求
    public synchronized boolean upDownRequestAhead(String buildingName, int floor, int velocity) {
        ...

    }
// 人都送到了
    public synchronized boolean noPersonLeft() {
        return personLeft == 0;
    }

Strategy类木有锁, 不互斥的给出运动方向、上下人

public interface Strategy {
    public Vector getPickUpRequests(Vector inside,
                                                   int floor, int dir, int capLeft);

    public boolean turnAround(Vector inside, int floor, int dir, int capacity);

}

InputHandler中的锁:

// 用于判停,判wait
private boolean checkWaitReturn() {
        synchronized (requestTable) {
            while (this.isempty() && requestTable.isLeftRightEmpty(floor)) {
                if (requestTable.isInputEnd() &&
                        requestTable.isLeftRightEmpty(floor) && requestTable.noPersonLeft()
                        && this.isempty()) {
                    requestTable.notifyAll();
                    return true;
                }
                try {
                    requestTable.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

主要就是锁住了RequestTable 防止 check & modify, read & write, write&write 的线程危险, 使得其互斥。

还有就是电梯在运行时需要查看一下情况,其实也可以放在RequestTable类里。

调度器设计

hw5的一个版本里, 我的调度器主要就是负责按楼层分发, 没有任何特殊性,感觉名存实亡就是摆设, 所以就舍弃了调度器线程。

我的调度器线程没了, 调度主要就是自由竞争。

同时换乘请求拆分时, 优化了一部分基准策略, 按概率随机分配拆分楼层, 使得拆分楼层分布保持较为均匀

bug与测试 总结

强测&互测bug

三次作业总共出现了一个bug, 就是我第一次作业最后提交的时候一着急, 不小心把上下人逻辑搞错了, 导致可以承载的人数过多,wa了好几个点,真的心痛, 血的教训。

debug最重要的是按部就班的按debug流程来, 不要着急,不能东一榔头西一棒槌,都可能错过你的bug.

ps: 中测真的很弱, 感觉就是把你骗进来杀
​ ————沃兹基朔德

比如在那以后我就规定了这么一套流程,防止我心急或者漏了什么,导致bug被miss过去, 看着图一乐吧,毕竟我真是太粗了, 这些流程守好了, 别丢东西了

OO第二单元总结

遇到的记忆深刻的bug

OO第二单元总结

本地测试与测评机

测评机三次作业都做了, 还和小伙伴一块分享一块测试, 真不戳!评测机也是不断迭代hhh

从最开始只能测一个人,到支持多个人一起pk速度

唯一不足就是对于超时应该及时掐断, 我还没来及整, python多线程有时间学一波吧

心得体会

线程安全心得

线程安全的心得在于,关键在于设计线程安全类, 通过线程安全类来保证各个线程的行为是安全的, 比如通过锁的方法保证互斥, 通过资源也同时完成了线程间的协作通信。 关键在于选取合适的临界区, 保证线程安全的情况下尽量小。

层次化设计&设计原则

三次作业基本是迭代的, 每次作业都在上次的作业上或是继承, 或是新增了一些功能, 较好的实现了代码复用

SRP: 职责应该单一,不要承担过多的职责。体现在每个类只负责自己的行为, 比如:

​ 电梯只负责开关门, 上下人, 停止, 转向, 前进。

​ RequestTable仅仅负责,根据电梯的信息进行搜索并返回数据,以及数据的更删查改。

​ InputHandler仅仅负责拿到请求、处理请求

OCP: 修改软件功能的时候,使得他不能修改我们原有代码,只能新增代码实现软件功能修改的目的。 可以从三次代码的结构是迭代的, 仅仅新增了部分代码, 实现代码复用。

ISP: 接口的内容一定要尽可能地小,能有多小就多小。 我将策略类的接口仅设置了2个方法,转向、上下人,最小限度的保持了策略类对电梯的控制

LSP, DIP: 体现在策略类的分离体现了 ,前面说过了,就不重复了

真情实感

做首诗纪念一下

电梯月
​ ——cywuuuu
欢送电梯月,
可惜有bug。
下次再努力,
争取bugfree!

Original: https://www.cnblogs.com/cywuuuu/p/16192583.html
Author: cywuuuu
Title: OO第二单元总结

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/714003/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 多项式求逆

    已知一度数为n的多项式(A(x))。 [A(x)B(x)\equiv1\pmod {x^n} ] (B(x))即为(A(x))的逆元。 多项式的除法、(\exp)和(\ln)都是基…

    技术杂谈 2023年6月21日
    0101
  • 线程池如何观测?这个方案让你对线程池的运行情况了如指掌!

    今天我们来聊一个比较实用的话题,动态可监控可观测的线程池实践。 这是个全新的开源项目,作者提供了一种非常好的思路解决了线程池的可观测问题。 这个开源项目叫: DynamicTp 地…

    技术杂谈 2023年7月11日
    083
  • Spring Ioc源码分析系列–前言

    Spring Ioc源码分析系列–前言 为什么要写这个系列文章 首先这是我个人很久之前的一个计划,拖了很久没有实施,现在算是填坑了。其次,作为一个Java开发者,Spr…

    技术杂谈 2023年7月25日
    080
  • 低代码如何构建支持OAuth2.0的后端Web API

    OAuth2.0 OAuth 是一个安全协议,用于保护全球范围内大量且不断增长的Web API。它用于连接不同的网站,还支持原生应用和移动应用于云服务之间的连接,同时它也是各个领域…

    技术杂谈 2023年5月31日
    089
  • 使用C#做为游戏开发的服务器语言方案

    Scut开源服务器 开源C#/Python/Lua 手游服务器 从2015-09-11不再更新。 前后端统一的游戏开发方案 Unity3D Client And C# Server…

    技术杂谈 2023年6月1日
    089
  • go逃逸分析

    我们在写代码的时候,有时候会想这个变量到底分配到哪里了?这时候可能会有人说,在栈上,在堆上。信我准没错… 但从结果上来讲你还是一知半解,这可不行,万一被人懵了呢。今天我…

    技术杂谈 2023年5月30日
    097
  • 工作经验总结

    最近一段时间,因为好多生活和工作上的事情,好久没有更新博客了。虽然我一直有很多的想法,可是大多数往往往往都会因为下面一些原因坚持不下去: 生活和工作琐事繁多 感觉个人技能还不熟练,…

    技术杂谈 2023年6月1日
    084
  • 医院HIS(LIS)系统时钟同步(NTP网络时间服务器)技术详解

    医院HIS(LIS)系统时钟同步(NTP网络时间服务器)技术详解 医院HIS(LIS)系统时钟同步(NTP网络时间服务器)技术详解 京准电子科技官微——ahjzsz NTP网络时间…

    技术杂谈 2023年6月21日
    080
  • Xperf Basics: Recording a Trace(转)

    The Windows Performance Toolkit, also known as xperf, is a powerful (and free!) set of too…

    技术杂谈 2023年5月31日
    084
  • 百行以内实现复杂数学表达式计算

    一改以前 本次先上代码 package good;//Evaluate complex expressionsimport java.io.IOException;import j…

    技术杂谈 2023年7月23日
    071
  • mean-shift算法详解(转)

    MeanShift最初由Fukunaga和Hostetler在1975年提出,但是一直到2000左右这篇PAMI的论文Mean Shift: A Robust Approach T…

    技术杂谈 2023年6月1日
    089
  • 动态规划-摘花生

    Hello Kitty想摘点花生送给她喜欢的米老鼠。 她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。 地里每个道路的交叉点上都有种着一株花生苗,上面有若干…

    技术杂谈 2023年7月11日
    086
  • 安装VMware Tools显示灰色的解决办法

    用VMware Workstation Pro好几年了,期间这个问题也遇到过好几次,这次把解决方案记录一下,若后续有其他情况其他解决方案将在此博文更新。 Step1:关闭虚拟机; …

    技术杂谈 2023年7月11日
    0126
  • ELK时间戳

    ELK时间戳 在我们使用ELK过程中,总会遇到时间戳的问题。首先 logstash如果没有加以处理的话,那么它默认使用的是采集的时间戳,然后存入 ES。那么这样的话时间显示的是错误…

    技术杂谈 2023年6月21日
    096
  • Spring Boot 通用对象列表比较和去重

    1、前言 在Excel批量导入数据时,常常需要与数据库中已存在数据的比较,并且需要考虑导入数据重复的可能性。 导入的行数据,一般有一个实体类(对象)与之对应,往往这个实体类在数据库…

    技术杂谈 2023年6月21日
    081
  • 学习链表复盘中

    链表基础知识 链表的分类 链表是一种通过指针串联在一起的线性结构,主要分为单链表、双向链表和循环链表。 单链表 单链表中每一个节点是由两部分组成,一个是数据域、一个是指针域(存放指…

    技术杂谈 2023年7月25日
    0103
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球