操作系统电梯调度项目
文章目录
一、项目简介
本项目旨在设计和实现一个基于操作系统相关知识的电梯调度程序,用于模拟管理一个20层楼的5部互联电梯系统。该系统应当支持多线程机制,以便实现多电梯之间的协同工作。在程序中应当设计数字键、关门键、开门键、上行键、下行键、报警键等按键,并为每个电梯及楼层设置相应的上行和下行按钮以及数码显示器,以便用户对电梯进行操作。通过该程序,电梯系统可以实现智能调度,高效地响应用户需求,提高电梯运行效率和用户体验。该程序的设计和实现涉及操作系统相关的知识和技能,如线程调度、同步机制、互斥锁等,以保证系统的正确性、高效性和稳定性。
二、技术栈
- 编程语言:Java
- 开发工具:Eclipse
- GUI库:javax.swing.*
- AWT库:java.awt.*
- 多线程:java.util.concurrent.*
三、界面设计
本电梯调度系统的GUI界面设计由左右两个区域组成。其中左侧为电梯控制及演示区,右侧为电梯运行信息区。
电梯控制及演示区包括:
- 顶部标签栏 banner,包含系统名称或者其他信息。
- 5部电梯 elevts,用 ElevatorSystem 类实现,每个 ElevatorSystem 对象代表一个电梯,共有5个电梯。
- 20个楼层标签 labels,用 JLabel 类实现,显示楼层数字。
- 20个楼层选择下拉框 chooseFloor,用 JComboBox 类实现,用于模拟乘客选择要去的楼层。
- 5部电梯对应的每个楼层状态按钮 elev,用 JButton 类实现,用于显示电梯运行状态,包括开门、关门、上行、下行、停止等状态。
- 20个上行请求按键 upBt,用 JButton 类实现,用于模拟乘客请求上行电梯,以及20个下行请求按键 downBt,用 JButton 类实现,用于模拟乘客请求下行电梯。
- 5个数码显像管 showfloor,用 JLabel 类实现,显示电梯当前楼层数。
- 查看帮助按钮 showHelp,用于查看系统使用帮助的内容。
电梯运行信息区包括:
- 输出提示信息 logs,用 TextArea 类实现,用于输出系统信息和调试信息。
整个界面设计包括了电梯调度系统的主要功能演示,包括电梯状态显示、乘客请求模拟、电梯运行控制等。同时也提供了帮助信息,方便用户使用。
四、调度算法
电梯对于按键操作的响应,主要通过如下的调度算法实现:
-
elevatorManager类的adjust()方法用于在多层楼之间调度电梯,以便最快地满足用户的请求。该算法根据电梯的当前状态和请求的目标楼层,将电梯向上或向下移动。具体而言,如果最优电梯的当前位置在目标楼层的下方,它将被调度向上移动,如果当前位置在目标楼层的上方,它将被调度向下移动,如果当前位置就是目标楼层,它将被调度停止。此外,该算法还记录了电梯的状态和运动轨迹,并使用 Thread.sleep() 方法控制电梯的运动过程。
-
在elevatorManager类中的run()方法实现的电梯调度算法采用了一个循环,在其中进行电梯调度。具体来说,该算法会对每个楼层的上升和下降请求队列进行轮询,检查可用且距离该楼层最近的电梯,并将该请求分配给该电梯。当有请求时,算法会遍历所有电梯,分别检查以下情况:
- 电梯当前状态为停止,且该请求队列不为空,此时可以直接将请求分配给该电梯。
- 电梯当前状态为下降,且该电梯的下降最低楼层小于等于该请求所在楼层,此时该电梯可以处理该请求。
- 电梯当前状态为上升,且该电梯的上升最高楼层大于等于该请求所在楼层,此时该电梯可以处理该请求。
在确定了最佳电梯之后,系统会调用 adjust() 方法来将请求分配给该电梯,并等待该电梯完成请求后再返回。算法中还使用了一个线程安全的标记数组 upqueLock 和 downqueLock 来确保在访问请求队列时不会出现竞态条件。此外,算法还使用了 Thread.sleep() 方法来限制调度算法的执行频率,避免资源过度消耗。
总的来说,本系统的电梯调度算法主要遵循下面的逻辑:当有一个乘客在某一楼层等待电梯时,算法将根据当前电梯的状态来决定哪个电梯将响应请求。如果有一个或多个电梯当前正在向上移动,并且它们的目标楼层高于或等于当前请求的楼层,则最接近当前楼层的电梯将响应请求。如果没有正在向上移动的电梯,但有静止的电梯,则最接近当前楼层的静止电梯将响应请求,并且该电梯将启动并向上移动,直到达到当前请求的楼层。对于下降请求,算法采用类似的逻辑,但是检查的是向下移动的电梯,如果没有正在向下移动的电梯,但有静止的电梯,则最接近当前楼层的静止电梯将响应请求,并且该电梯将启动并向下移动,直到达到当前请求的楼层。如果没有符合条件的电梯,则请求将等待,直到符合条件的电梯出现。这个算法的目的是尽可能快地响应乘客的请求,并确保每个电梯的运行效率最大化。
五、功能实现
5.1基本变量
GUIwindow类下有如下基本变量,其基本功能如表格所示:
变量名 | 类型 | 描述 |
---|---|---|
banner | JLabel[] | 顶部标签栏数组,包含9个JLabel |
elevts | ElevatorSystem[] | 电梯系统数组,包含5个ElevatorSystem对象 |
labels | JLabel[] | 楼层标签数组,包含20个JLabel |
upqueue | ArrayList[] | 上升请求队列数组,包含20个ArrayList对象 |
downqueue | ArrayList[] | 下降请求队列数组,包含20个ArrayList对象 |
chooseFloor | JComboBox[] | 楼层选择按键数组,包含20个JComboBox对象 |
elev | JButton[][] | 每部电梯对应的每个楼层的状态数组,包含5行20列的JButton对象 |
upBt | JButton[] | 上楼按键数组,包含20个JButton对象 |
downBt | JButton[] | 下楼按键数组,包含20个JButton对象 |
showfloor | JLabel[] | 数码显示管显示楼层数数组,包含5个JLabel对象 |
logs | TextArea | 输出提示信息的TextArea对象 |
elevators | ArrayList | 电梯组,包含多个ElevatorSystem对象 |
upqueLock | boolean[] | 上升请求队列的锁数组,包含20个boolean值 |
downqueLock | boolean[] | 下降请求队列的锁数组,包含20个boolean值 |
showHelp | JButton | 选择查看帮助的按钮对象 |
Help | String | 帮助文本的字符串对象 |
ElevatorSystem类有如下变量,其基本功能如表格所示:
变量名 | 数据类型 | 描述 |
---|---|---|
name | int | 电梯编号 |
currentState | int | 电梯当前运动状态 停止:0 上升:1 下降:-1 |
emerState | int | 电梯紧急状态 |
currentFloor | int | 电梯当前所在层数 |
maxUp | int | 电梯要去的最高楼层 |
minDown | int | 电梯要去的最低楼层 |
cmpUp | Comparator | 升序选择器 |
cmpDown | Comparator | 降序选择器 |
upStopList | Queue | 下降停止队列 |
downStopList | Queue | 上升停止队列 |
buttonList | JButton[] | 按钮队列(ui) |
showfloor | JLabel | 显示楼层的数码显像管 |
5.2电梯运行(上升、下降)功能
电梯运行主要通过ElevatorSystem类的run()方法实现。以上升状态的电梯为例,如果电梯的currentState为1,表示电梯处于上行状态。进入循环后,需要完成下面一些任务:如果当前楼层有乘客需要进电梯或者有乘客要出电梯,电梯门会打开。接下来电梯会载上向上和向下的乘客,停留一段时间后电梯关门,如果电梯内乘客走空或者电梯到达顶端,电梯currentState会变为0,电梯停止运行,然后电梯开门。每一次循环及每一次电梯运行(上一层楼)都会改变当前楼层变量currentFloor、下面一层楼和当前楼的状态(图标、颜色)以及最下方的电梯楼层数码显示管。同时全过程运行区输出每一次电梯状态改变的信息。
例如:当有乘客在6楼点击了上楼按钮时。
演示区电梯会依次运行至6楼后开门:
运行信息区:
5.3楼层上下按钮功能
楼层上下按钮功能主要用于乘客在某一楼层需要调度电梯来满足自己上楼或者下楼的需求。当乘客点击向上的三角形按钮或者向下的三角形按钮时,电梯会自动运行至当前乘客所在的楼层,等待乘客接下来选择需要前往的楼层。
具体实现代码如下:
ImageIcon originIcon1 = new ImageIcon(GUIwindow.class.getResource("/images/上箭头.png"));
ImageIcon up_arrow = new ImageIcon(originIcon1.getImage().getScaledInstance(30, 30, Image.SCALE_SMOOTH));
ImageIcon originIcon2 = new ImageIcon(GUIwindow.class.getResource("/images/下箭头.png"));
ImageIcon down_arrow = new ImageIcon(originIcon2.getImage().getScaledInstance(30, 30, Image.SCALE_SMOOTH));
// 上楼键初始化
upBt[i] = new JButton();
for(int j=0;j<20;j++) {
upBt[i].setBackground(new Color(255,208,232));
upBt[i].setIcon(up_arrow);
}
final int nowfloor=i;
upBt[i].addActionListener(e -> {
upqueue[nowfloor].add(nowfloor+1);
labels[nowfloor].setBackground(Color.GREEN);
logs.append("第" + (nowfloor + 1) + "楼有人要上楼\n");
});
// 下楼键初始化
downBt[i] = new JButton();
for(int j=0;j<20;j++) {
downBt[i].setBackground(new Color(255,208,232));
downBt[i].setIcon(down_arrow);
}
final int nowfloor1=i;
downBt[i].addActionListener(e -> {
downqueue[nowfloor1].add(nowfloor1+1);
labels[nowfloor1].setBackground(Color.GREEN);
logs.append("第" + (nowfloor1 + 1) + "楼有人要下楼\n");
});
首先,代码加载上行箭头和下行箭头的图片,并将它们缩放到指定大小。然后,使用for循环将按钮的背景颜色设置为浅粉色,并将按钮的图标设置为箭头图标。每个按钮都添加一个动作监听器,当按钮被按下时,将相应的楼层加入到相应的上行/下行队列中,并在日志文本区域中记录相应的事件。
5.4电梯报警按钮功能
电梯报警按钮主要用于测试部分电梯故障的情况,当某个电梯处于报警状态时,表明该电梯出现故障,则该电梯应该立刻停止运行。
具体实现代码如下:
elev[i][0].setText("正常");
// 故障/正常
elev[i][0].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();
int elevatorIndex = -1;
// 根据点击的按钮确定是哪个电梯的故障/正常按钮
for (int k = 0; k < 5; k++) {
if (button == elev[k][0]) {
elevatorIndex = k;
break;
}
}
if (elev[elevatorIndex][0].getText().equals("正常")) {
elev[elevatorIndex][0].setText("报警");
elev[elevatorIndex][0].setBackground(Color.RED);
elevts[elevatorIndex].setCurrentState(-2);
logs.append("电梯" + (elevatorIndex + 1) + "故障,暂时无法使用\n");
} else {
elev[elevatorIndex][0].setText("正常");
elev[elevatorIndex][0].setBackground(Color.GREEN);
elevts[elevatorIndex].setCurrentState(2);
logs.append("电梯" + (elevatorIndex + 1) + "恢复正常运行\n");
}
}
});
首先,使用setText()方法将电梯的状态设置为"正常",表示电梯正常运行。
然后,通过addActionListener()方法添加一个ActionListener监听器,监听故障/正常按钮的点击事件。当故障/正常按钮被点击时,会根据被点击的按钮确定是哪个电梯的故障/正常按钮。如果当前电梯的状态为正常,则将状态设置为"报警",并将按钮的背景色设置为红色,表示电梯出现故障;同时将电梯的状态设置为-2,表示电梯停止运行。如果当前电梯的状态为报警,则将状态设置为"正常",将按钮的背景色设置为绿色,表示电梯已恢复正常运行;同时将电梯的状态设置为2,表示电梯重新开始运行。
最后,代码通过调用logs的append()方法将日志信息输出到GUI界面上,记录电梯状态的改变。
5.5开门关门功能
该功能是为了演示对应电梯的开关门操作,点击某个电梯的开关门按钮后,该按钮颜色会改变,并且电梯门状态也会实时显示更新。同时该电梯的开关门信息也会显示在右侧电梯信息运行信息区。注意,电梯自动运行时的开关门由系统自动控制,无需点击按钮。
具体代码如下:
// 开门/关门
elev[i][1].setText("关门");
elev[i][1].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();
int elevatorIndex = -1;
// 根据点击的按钮确定是哪个电梯的开门/关门按钮
for (int k = 0; k < 5; k++) {
if (button == elev[k][1]) {
elevatorIndex = k;
break;
}
}
if (elev[elevatorIndex][1].getText().equals("关门")) {
elev[elevatorIndex][1].setText("开门");
elev[elevatorIndex][1].setBackground(Color.YELLOW);
logs.append("电梯" + (elevatorIndex + 1) + "开门\n");
} else {
elev[elevatorIndex][1].setText("关门");
elev[elevatorIndex][1].setBackground(Color.GRAY);
logs.append("电梯" + (elevatorIndex + 1) + "关门\n");
}
}
});
5.6查看帮助信息功能
如果用户对使用本电梯调度系统有任何疑问,都可以通过点击左屏幕右下角的求助按钮来查看帮助信息,从而得到具体的操作指引以及功能介绍。
六、项目总结
本项目较好地利用操作系统的多线程编程的相关知识实现了电梯调度的系统。通过学习和选取特定的调度算法,使本系统能够较为真实的模拟现实中的电梯运行情况。同时在GUI设计方面使用了比较清晰易懂的图标、按钮等,使用户更加易于使用。整体上,本项目可以作为一个可行的电梯调度系统,在具体实现细节上还需要考虑到实际情况和用户体验等再做修改。