本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
在实现了先来先服务(FCFS)算法之后能够明显的感觉到先来先服务算法将当前处于就绪队列队首的那个进程调度到运行状态。也就是说,先来先服务算法只考虑作业或进程进入就绪队列的时间先后,而不考虑它的下一个CPU周期的长短等其他因素。虽然先来先服务算法简单易行并且是一种非抢占式策略,但性能却不大好导致平均周转时间特别长。因此,在先来先服务的算法基础上提出了短作业优先(SJF)算法来改进先来先服务算法,来减少平均周转时间。本文将介绍如何用Java来简单实现短作业优先调度算法
提示:以下是本篇文章正文内容,下面案例可供参考
代码实现
假设当前有四个进程先后到达系统进行调度:
作业名 | 到达时间 | 服务时间 |
---|---|---|
A | 0 | 20 |
B | 5 | 15 |
C | 10 | 5 |
D | 15 | 10 |
经过计算可得到如下结果:
作业名 | 到达时间 | 服务时间 | 完成时间 | 周转时间 | 带权周转时间 |
---|---|---|---|---|---|
A | 0 | 20 | 20 | 20 | 1 |
B | 5 | 15 | 50 | 45 | 3 |
C | 10 | 5 | 25 | 15 | 3 |
D | 15 | 10 | 35 | 20 | 2 |
平均周转时间: ( 20 + 15 + 20 + 45 ) / 4 = 25 | |||||
平均带权周转时间:( 20 / 20 + 15 / 5 + 20 / 10 + 45 / 15 ) / 4 = 2.25 |
接下来编写Java程序,输出以上计算结果
1、作业类
代码如下(示例):
class ProcessData {
// 到达时间
public int arriveTime;
// 服务时间
public int serviceTime;
// 完成时间
public int finishTime;
// 周转时间
public int turnTime;
// 带权周转时间
public double powerTime;
public ProcessData(int arriveTime, int serviceTime) {
this.arriveTime = arriveTime;
this.serviceTime = serviceTime;
}
@Override
public String toString() {
return arriveTime + "\t" +
serviceTime + "\t" +
finishTime + "\t" +
turnTime + "\t" +
powerTime;
}
}
2、算法实现类
代码如下(示例):
public class ProcessProject {
// 平均周转总时间
public static double avgTotalTime;
// 平均带权周转时间
public static double avgPowerTime;
public static void main(String[] args) {
ProcessData[] processData = new ProcessData[4];
// 定义四个作业
processData[0] = new ProcessData(0, 20); // 作业A
processData[1] = new ProcessData(5, 15); // 作业B
processData[2] = new ProcessData(10, 5); // 作业C
processData[3] = new ProcessData(15, 10); // 作业D
// 短作业优先
SJF(processData);
}
// 短作业优先算法
private static void SJF(ProcessData[] processData) {
int preFinished = 0; // 前一个作业的完成时间即下一个作业的开始时间
avgTotalTime = 0; // 平均周转时间
avgPowerTime = 0; // 平均带权周转时间
for (int i = 0; i < processData.length; i++) {
processData[i].finishTime = 0; // 设置完成时间为0
processData[i].turnTime = 0; //周转时间
processData[i].powerTime = 0; //平均周转时间
}
int number = 0; // 定义作业号
// 定义双层for循环用于比较作业的完成时间和服务时间
for (int i = 0; i < processData.length; i++) {
int min = 8888;
for (int j = 0; j < processData.length; j++) {
/**
* 1. 如果服务时间小于最小时间
* 2. 到达时间小于等于前一个作业的完成时间
* 3. 完成时间为0代表着还没有进行服务
* 最核心的地方就在于有完成时间限制着作业不会继续重复进入循环
*/
if (processData[j].serviceTime < min && processData[j].arriveTime <= preFinished && processData[j].finishTime == 0) {
min = processData[j].serviceTime; // 将目前服务时间最短的作业的服务时间赋值给作业的最小完成时间
number = j; // 将下一个进行调度的作业号赋值给number
}
}
processData[number].finishTime = preFinished + processData[number].serviceTime; // 当前作业的完成时间等于上一个作业的完成时间加当前作业的服务时间
preFinished = processData[number].finishTime; // 将上一个作业的完成时间赋值为当前作业的完成时间
processData[number].turnTime = processData[number].finishTime - processData[number].arriveTime; // 周转时间 = 完成时间 - 到达时间
processData[number].powerTime = processData[number].turnTime / processData[number].serviceTime; // 带权周转时间 = 周转时间 / 服务时间
}
System.out.println("短进程优先算法:");
Display(processData);
}
// 该方法用于将作业的各种信息进行打印
private static void Display(ProcessData[] processData) {
System.out.println("到达时间\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);
}
}
3、运行结果
总结
以上便是短作业优先调度算法的Java实现,短作业优先算法的核心在于当系统中正在调度一个作业时,在当前作业调度完成之前到达系统的作业将会进行服务时间的比较,服务时间短的作业将在当前作业调度完成后优先进行调度。