前几天上课操作系统实验课课用java做了实现一下SPF短进程优先调度算法,代码水平很低,适合新手理解,在这里分享一下我的代码,希望能帮助到同学们,(彭彩虹老师的操作系统实验课速进)
算法描述
进程类
class ProcessData {
//作业号
public int id;
// 到达时间
public int arriveTime;
// 服务时间
public int serviceTime;
//开始时间
public int runtime;
// 完成时间
public int finishTime;
// 周转时间
public int turnTime;
// 带权周转时间
public double powerTime;
//判断是否处理过
public boolean finish=false;
// 作业的构造方法中传来的初值为到达时间和服务时间
public ProcessData(int id,int arriveTime, int serviceTime) {
this.id=id;
this.arriveTime = arriveTime;
this.serviceTime = serviceTime;
}
// 重写toString方法便于之后的数据展示
@Override
public String toString() {
return id + "\t" +
arriveTime + "\t" +
serviceTime + "\t" +
runtime + "\t" +
finishTime + "\t" +
turnTime + "\t" +
powerTime;
}
public String qString() {
return id + "\t" +
arriveTime + "\t" +
serviceTime + "\t" ;
}
}
运行主类
主要的算法思想是,设置一个从零到所有作业结束的时间节点,循环每个时间点,判断当前时间系统是否空闲且是否有作业到达,有作业到达则将到达的作业根据服务时间排好序,设置相应的系统释放时间即下一个系统空闲时间,在下一个系统空闲时间重复该步骤。
代码很长,但注释尽可能详细了
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ProcessProject {
// 平均周转时间
public static double avgTotalTime;
// 平均带权周转时间
public static double avgPowerTime;
public static void main(String[] args) {
// 定义长度为4,类型为作业数据类的作业数组用于存储4个作业
ProcessData[] processData = new ProcessData[4];
// 定义三个个作业作业号,到达时间,服务时间
processData[0] = new ProcessData(1,0,2);
processData[1] = new ProcessData(2,1,3);
processData[2] = new ProcessData(3,2,1);
processData[3] = new ProcessData(4,4,3);
// 调用SPF算法
SPF(processData);
}
//SPF算法方法
private static void SPF(ProcessData[] processData) {
int preFinished = 0; // 前一个作业的完成时间即为下一个作业的开始时间
int nextrelease=0;//下一次的释放时间
int end=0;//运行总时间
boolean isrelease=false;//判断系统当前是否释放即判断能否运行作业
avgTotalTime = 0; // 平均周转时间
avgPowerTime = 0; // 平均带权周转时间
ProcessData p;//用于队列位置交换的对象
// 初始化完成时间、周转时间、带权周转时间的初值为0
for (int i = 0; i < processData.length; i++) {
processData[i].finishTime = 0; // 设置初始完成时间为0
processData[i].turnTime = 0; // 设置初始周转时间为0
processData[i].powerTime = 0; // 设置初始带权周转时间为0
}
//初始化结束时间
for(int i=0;i<processData.length;i++) {
end=end+processData[i].serviceTime;
}
//一下两个list用于临时排序
List<ProcessData> list=new ArrayList<ProcessData>();
List<ProcessData> temp=new ArrayList<ProcessData>();
//SPF排序算法
for(int time=0;time<=end;time++) {//time为时间
//判断当前是否释放
if(time==0||time>=nextrelease) {
isrelease=true;
}
//如果释放了则跳到下个时间节点
if (!isrelease) {
continue;
}
//将队列中的作业在该时间下已经到达的作业加入到临时队列
for(int i=0;i<processData.length;i++) {
if(processData[i].arriveTime<=time&&!processData[i].finish) {
temp.add(processData[i]);
}
}
//同一时间下根据服务时间排序
if(temp.size()==0) {
continue;
}if (temp.size()==1) {
//用于跳过服务时间排序
}else {
for(int j=0;j<temp.size()-1;j++) {
for(int k=0;k<temp.size()-1;k++) {
if(temp.get(k).serviceTime>temp.get(k+1).serviceTime) {
p=temp.get(k);
temp.set(k, temp.get(k+1));
temp.set(k+1, p);
}
}
}
}
//将临时队列中的最服务时间最短的作业处理
if(temp.size()>0) {
temp.get(0).finish=true;//将作业的finsh属性设置为true,代表该作业已经被处理,下一个时间节点将不会考虑
nextrelease=nextrelease+temp.get(0).serviceTime;//设置下一次系统空闲的时间节点
list.add(temp.get(0));
}
if (time<nextrelease) {//决定系统是否释放
isrelease=false;
}
temp=new ArrayList<ProcessData>();//清空temp,用于下一个时间节点
}
//将作业处理顺序重新存入processDa[]队列中
for(int i=0;i<list.size();i++) {
processData[i]=list.get(i);
}
// 如果第一个作业的到达时间不等于前一个作业的完成时间,就将前一个作业的完成时间定义为当前作业的到达时间
if (processData[0].arriveTime != preFinished) {
preFinished = processData[0].arriveTime;
}
for (int i = 0; i < processData.length; i++) {
//开始时间计算
if(preFinished<processData[i].arriveTime) {//当前一个作业已完成,而且第二个作业未到时
processData[i].runtime=processData[i].arriveTime;
preFinished=processData[i].arriveTime;
}else {//否则该作业的开始时间为上一个作业的完成时间
processData[i].runtime=preFinished;
}
// 作业的完成时间为上一个作业的完成时间加当前作业的服务时间
processData[i].finishTime = preFinished + processData[i].serviceTime;
preFinished = processData[i].finishTime;
// 周转时间 = 完成时间 - 到达时间
processData[i].turnTime = processData[i].finishTime - processData[i].arriveTime;
// 带权周转时间 = 作业的周转时间 / 系统提供服务的时间
processData[i].powerTime = (double) processData[i].turnTime / (double) processData[i].serviceTime;
}
System.out.println("SPF算法:");
// 打印进程的信息
Display(processData);
}
private static void Display(ProcessData[] processData) {
System.out.println("进程号\t" +"到达时间\t" + "运行时间\t" + "开始时间\t"+ "结束时间\t" + "周转时间\t" + "带权周转时间\t");
for (int i = 0; i < processData.length; i++) {
System.out.println(processData[i]);
avgTotalTime += processData[i].turnTime; // 求总周转时间,此时avgTotalTime中存储的值为总周转时间
avgPowerTime += processData[i].powerTime; // 求总带权周转时间,此时avgPowerTime中存储的值为总带权周转时间
}
avgTotalTime = avgTotalTime / processData.length; // 平均周转时间
avgPowerTime = avgPowerTime / processData.length; // 平均带权周转时间
System.out.println("平均周转时间:" + avgTotalTime);
System.out.println("平均带权周转时间:" + avgPowerTime);
}
}
效果图