• Java实现目的选层电梯的调度


    一、前言

    本次博客我将简单介绍一下前两次的电梯作业,并简单解析一下我的程序结构,进一步对我的第二次作业的算法核心和一些想法做一些分享,我的电梯设计算法并不是由调度器来决定电梯的捎带与否,而是由电梯自主判断,在没有人员限制与其他条件的情况下,电梯自行判断电梯外是否有人以及是否需要捎带。

    二、电梯作业的介绍

    北航面向对象的课程第二单元要求设计一个载客电梯,该电梯为目的选层电梯,即需要使用电梯的人在未进入电梯时便已经输入自己要去的楼层(该种电梯已经在一些办公楼中投入使用),我们的任务是要实现它的调度算法,以实现最快最好运送完所有乘客,乘客的请求会在电梯运行过程红不断提出,我们则需要根据他们的请求控制电梯的运行,开关门,上下乘客。

    三、第一、二次电梯作业的架构逻辑

    简单的电梯作业不考虑电梯的最大载客量和电梯可去楼层的限制,用多线程的方法实现,是一个经典的生产者-消费者模型,可以设计一个请求池,乘客这个群体视为生产者,不断将请求放入池中,而电梯即使消费者,通过运行来满足乘客请求,视为将请求取走,因此完全是一个标准的生产者-消费者模型,因此我们创建一个Elevator电梯类作为实现电梯动作的载体,即消费者,创建一个Input类从终端接受请求,并将请求不断加入请求池中,即生产者,另外创建一个Dispatcher类,调度器,在第一次作业中调度器主要承担请求池的角色,而我们的请求池则是一个Queue队列,来存放和提供请求。

    第一次作业UML类图如下:

    主类中是一个死循环,不断从Input中接受请求,将请求放入Dispatcher,其中值得一提的是由于Input和Elevator都需要不断调用调度器,因此Dispatcher实现单例模式,以保证线程的安全,每一次循环创建一个接受请求的线程和执行电梯动作的线程,Operate是一个线程类,Elevator也是单例模式,接受Operate的调用,结束的标志是Input接受到null后返回一个标志表示请求结束,而后便跳出死循环结束程序

    第一次作业的调度算法是傻瓜调度,即接受一个完成一个,按顺序执行请求,不存在捎带,这样的执行效率也毫无疑问是最低的,但是实现起来非常简单,不再赘述

    这里值得一提的是单例模式

    单例模式,毫无疑问,从名字上就可以明白即对于一个类来说在整个程序中只创建一个实例,不允许创建多个实例,每次只能调用一个实例,对于共享的资源和需要重复调用的代码块使用synchronized关键字保护起来,单例模式是多线程设计中最为基础和常见的一个模式,很好的保证了线程的安全,它的优点便是对于这种需要不安全的类实现了线程安全,但是缺点也显而易见,对于公用的代码块或共享的数据资源,如果有一个线程在用,那么其他所有线程都必须在这里等待,必须等前一个线程用完后才可继续执行,浪费了线程执行的时间;其次这样的先到先得也破坏了线程之间的优先级,如果线程并发有优先级的限制,那么毫无疑问单例模式不能胜任这样的任务,而信号量的机制,wait和notify的使用都可以解决这一问题。

    第二次作业UML类图如下:

    整体架构与第一次作业没有任何差别,因此不再赘述

    设计思想有一些改变,首先调度器需要与电梯产生更多的交互,这要从我们的电梯说起,本次作业的电梯需要实现ALS即捎带策略,那我的想法是由电梯自行决定是否捎带,创建一个数组,对应每一楼层外的等待人数,例如如果8层有一个人按下了请求,那么floor[8]就会+1,如果这一层的人上了电梯,那么floor[8]就会-1。那么电梯每次执行都需要分两步,1.判断运行方向,运行方向有三种:向上,向下,停下,如果楼层外有人,或者电梯里有人要出来就停止运行,否则,根据电梯里所有请求的目的楼层离电梯目前楼层最近的那个楼层确定电梯向上or向下运行。2、在判断完运行方向后,如果向上或向下,那么直接输出相关信息,如果电梯停下,那么一定有人要进或者有人要出,先判断是否有人出去,遍历一下电梯中的人的目的楼层,如果有等于当前楼层的,就开门,先让要出的人出去,随后判断是否有人要进入,如果电梯外的人的请求运行方向与电梯下一步的运行方向一致,便让人进来,随后关上电梯,并且根据电梯下一步运行方向执行向上或向下操作。

    优化:以上是我的设计算法,但是这样的捎带策略未必会达到时间上的最优,因为我判断电梯运行方向的方式是根据电梯里所有人的目的楼层离当前楼层最近的那一位而确定的,但是这样的算法可能会出现多次折返的情况,因此,我想如果每次按电梯里所有人中离当前楼层最远的那个楼层来确定执行方向,这样最多两次折返即可完成电梯中所有人的请求,虽然在一些小规模数据上性能并不一定优于之前的设计,甚至可能还差一点,但是不会出现那种极端的不断折返的情况,提高了电梯调度的可靠性。

    四、第三次作业的任务分配算法

    在讨论课上很多同学出现了A,B电梯任务繁重但是C电梯任务很轻的极大反差,请求任务的不均分配一定会降低电梯执行的效率,那么如何合理分配任务给电梯呢?我在这里提出我的一些想法:调度器中创建三个请求池,每一个请求队列对应一个电梯,这样每个电梯相互独立,只会执行自己任务队列中的任务,请求来的时候就确定加入哪一个请求队列,也就确定了任务的分配,那么如何公平分配任务呢?首先给每个任务队列对应一个变量,该变量是队列中任务个数与电梯容量的比值,即任务越多,电梯越小,那么该值就会越大,每次来一个任务时,先判断是否存在某两个电梯之间的变量值之差超过了0.5,如果是,则让任务轻的电梯接任务,如果该电梯不可以独立完成,便确定两电梯合作的汇合交接地点进而确定交接。如果没有,则判断是否可以由电梯独立完成,可以便让可以独立完成并且值相对小的电梯接任务,如果否,便确定两个合作的电梯,确定的原则还是值相对小的两个电梯合作接任务,将请求拆分分别加入两个请求队列,对请求队列中的每个请求设置有效值,只有前一个请求完成,后一个请求才有效可以执行,否则电梯会一直忽略该任务,知道该请求有效。

  • 相关阅读:
    Lamp环境搭建
    jquery之下拉列表select
    jquery之radio
    php连接postgresql
    ipython的notebook
    python连接postgresql数据库
    django最简单表单入门
    css制作简单下拉菜单
    下拉列表简单操作
    css制作最简单导航栏
  • 原文地址:https://www.cnblogs.com/oocj/p/buaaoo_homework_unit_2.html
Copyright © 2020-2023  润新知