模拟内容
利用Java语言,模拟进程的调度过程,本篇博客中将通过先来先服务算法可视化模拟进程的调度过程,并且在模拟的过程中展示出就绪队列、阻塞队列、执行状态。
实验原理(理论)
先来先服务算法是最简单的调度算法,既可以用于作业调度 ,也可以用于程序调度,当作业调度中采用该算法时,系统将按照作业到达的先后次序来进行调度,优先从后备队列中,选择一个或多个位于队列头部的作业,把他们调入内存,分配所需资源、创建进程,然后放入“就绪队列”,直到该进程运行到完成或发生某事件堵塞后,进程调度程序才将处理机分配给其他进程。
先来先服务算法的服务要领是:按照进程进入就绪队列的先后顺序调度并分配处理机执行。先来先服务调度算法是一种非抢占式的算法,先进入就绪队列的进程,先分配处理机运行。一旦一个进程占有了处理机,它就一直运行下去,直到该进程完成工作或者因为等待某事件发生而不能继续运行时才释放处理机。
实验步骤及代码分析
1.任务定义
使用java编写可视化程序,通过在界面中绘制四个小球来模拟进程的调度,同时绘制其他形状的图形来代表就绪队列和CPU。点击“开始按钮”让小球以不同的速度(随机产生)开始运动,最先到达“CPU”边缘的小球优先通过“CPU”,其余的小球在“就绪队列”中等待,直到CPU空闲下一个小球继续向“CPU”运动。通过点击按钮“重置并开始”来恢复界面的初始状态并开始新的模拟过程。
2.界面设计
初始界面如下图所示,界面中有四个小球、两个长方形区域、一个正方形区域以及三个按钮。四个小球用来模拟四个进程的执行和调度过程,第一个长方形区域代表就绪队列,第二个长方形区域用来表示进程由就绪状态到执行状态的转变,正方形区域代表CPU,三个按钮分别是“开始”、“重置并开始”、“退出”。
3.算法设计
定义一个队列BallQueue用于存放小球,小球在开始运动时会随机获得不同的速度,这时会根据小球速度的大小来判断其进入队列的先后次序,速度大的先进入队列,速度小的后进入队列,从而以小球在队列中的顺序表示小球到达的先后次序。位于队头的小球首先开始运行,直到其通过“CPU”,然后将其从队列中移出。每个小球在到达就绪队列时会判断自己是否位于队头,若是则开始(或继续)向前运动直到通过“CPU”,然后从队列中移出;若不是则在“就绪队列”中等待,直到队列为空,这时意味着所以的小球都已经通过了“CPU”,之后CPU空闲,模拟结束。
4.主要代码及解释如下所示:
(1)首先需要定义一个小球类Ball,其包含x、y和speed三个属性值,分别表示小球在panel中的横坐标、纵坐标和运动的速度。
class Ball{
int x;
int y;
int speed;
public Ball(int x,int y,int speed){
this.x=x;
this.y=y;
this.speed=speed;
}
public int getY() {
return y;
}
public int getX() {
return x;
}
}
(2)定义Panel类,其继承自JPanel类,除了需要在其构造函数中将控件加入panel外,还需要定义用于改变小球坐标的go()方法,同时还要重写Panel的paint()方法,用来根据小球的坐标在panel中重绘小球。
public void go(int n,Ball ball){
if(ball_x[n]<400){
ball_x[n]=ball_x[n]+ball_speed[n]*5;
ball.x=ball_x[n];
}
else{
if(BallQueue.peek()==ball){
if(ball.x<830) {
ball_x[n] +=30;
ball.x = ball_x[n];
ball.y=270;
}
else if(ball.x<980){
ball_x[n] +=10;
ball.x = ball_x[n];
label.setText("进程"+(n+1)+"正在使用CPU");
}
else {
BallQueue.remove();
label.setText("CPU空闲,即将调度下一个进程");
}
}
}
if(BallQueue.size()==0) {
label.setText("执行结束,CPU空闲");
}
}
重写repaint()方法,并在其中根据“CUP”的使用情况显示相应的提示信息:
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.pink);
g.fillRect(390,20,70,500);
g.setColor(Color.GREEN);
g.fillRect(460,260,370,70);
g.setColor(Color.white);
g.setFont(new Font("宋体",Font.BOLD,25));
g.drawString("就",410,50);
g.drawString("绪",410,80);
g.drawString("队",410,110);
g.drawString("列",410,140);
g.setColor(Color.BLUE);
g.fillRect(830,220,150,150);
g.setColor(Color.black);
g.setFont(new Font("宋体",Font.BOLD,50));
g.drawString("CPU",870,310);
g.setColor(Color.cyan);
g.fillOval(ball1.getX(),ball1.getY(),50,50);
g.setFont(new Font("宋体",Font.BOLD,15));
g.drawString("进程1",ball1.getX(),(ball1.getY()-20));
g.setColor(Color.ORANGE);
g.fillOval(ball2.getX(),ball2.getY(),50,50);
g.drawString("进程二",ball2.getX(),(ball2.getY()-20));
g.setColor(Color.black);
g.fillOval(ball3.getX(),ball3.getY(),50,50);
g.drawString("进程三",ball3.getX(),(ball3.getY()-20));
g.setColor(Color.gray);
g.fillOval(ball4.getX(),ball4.getY(),50,50);
g.drawString("进程四",ball4.getX(),(ball4.getY()-20));
}
(3)定义线程类BallThread,其继承自Thread,每一个小球的运动开启一个线程。该类的一个属性值为Panel类型。BallThread对象通过Panel中的go()方法改变小球的坐标,通过Panel中的paint()方法来绘制小球的位置。
class BallThread extends Thread{
public Panel panel;
public Ball ball;
public int n;
public BallThread(Panel panel,Ball ball,int n) {
this.panel=panel;
this.ball=ball;
this.n=n;
}
public void run(){
while (true){
panel.go(n,ball);
panel.repaint();
try {
sleep(80);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
附录程序清单
fcfs.java清单:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.Queue;
public class fcfs {
public static void main(String[] arg)