短作业优先调度算法(Short Job First)用于进程调度时又被称为短进程优先调度算法(Short Process First),该算法既可以用于作业调度,又可以用于进程调度。
在作业调度中,该算法每次从后备作业队列中挑选估计服务时间最短的一个或几个作业,将他们调入内存,分配必要的资源,创建进程并放入就绪队列。在进程调度中的原理类似。
题目:
每个任务请求都以其请求时间(向系统提交请求的时间)和 其持续时间(即完成任务所需要的时间)为特征。
当前任务完成后,SJF 策略选择具有最短持续时间的任务作为下一个要执行的任务。如果多个任务都有最短持续时间,则选择请求时间最早的那个任务,任务的的等待时间为请求时间和时间开始时间的差值(即,等待系统执行任务所花的时间)。假设任务到达时系统时钟处于执行任务的状态,且永远不会关闭。
给定的一个请求时间和任务持续时间的列表,计算使用最短作业优先(SJF)算法调度时的平均等待时间。
所给出的请求时间和持续时间都是按照请求时间的升序排序的。
ShortFirstJob类,有一个方法minAgerageWaitTime(int[] requestTime, int[] durationTime) requestTime是n个任务的请求时间,durationTime是n个任务的持续时间。该方法返回一个表示平均等待时间(使用非抢占式SJF调度算法)的浮点数。
(假定0 <= 到达时间 < 100.0 < 突发时间 < 100)
注:
优先选择持续时间小的,如果持续时间相同,则选择请求时间小的。
- 提交时间 = 请求时间
- 服务时间 = 作业需要运行的时间,即持续时间
- 开始时间 = task == 0 ? 0 : 上个优选任务 完成时间
- 完成时间 = 开始时间 + 服务时间
- 等待时间 = 开始时间 - 提交时间
- 周转时间 = 完成时间 - 提交时间
- 带权周转时间 = 周转时间 / 服务时间
- 响应比 = (等待时间 + 服务时间) / 服务时间 = 等待时间/服务时间 + 1
例如:
requestTime = {0, 2, 4, 5}; //请求时间
durationsTime = {7, 4, 1, 4}; // 持续时间
作业名 | 提交时间 | 服务时间 | 开始时间 | 完成时间 | 等待时间 | 周转时间 | 带权周转时间 |
---|---|---|---|---|---|---|---|
1 | 0 | 7 | 0 | 7 | 0 | 7 | 7/7 |
2 | 2 | 4 | 8 | 12 | 6 | 10 | 10/4 |
3 | 4 | 1 | 7 | 8 | 3 | 4 | 4/1 |
3 | 5 | 4 | 12 | 16 | 7 | 11 | 11/4 |
由上面的调度表可以知道,SJF算法的调度顺序为1->3->2->4;
平均等待时间:(0 + 6 + 3 + 7) / 4 = 4
平均周转时间和平均带权周转时间同理可以计算。
代码如下: 输出 4.0
</pre><pre name="code" class="java">package wn.kaoshi;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;public class ShortJobFirst {public static float minAgerageWaitTime(int[] requestTime, int[] durationTime){int length = requestTime.length;int[] serviceTime = new int[length]; //服务时间 即是持续时间for(int i=0; i<length; i++){serviceTime[i] = durationTime[i]; }int[] task = new int[length]; //任务号for(int i=0; i<length; i++){task[i] = i+1;}int[] waitTime = new int[length]; //等待时间int[] startTime = new int[length]; //开始时间int[] finishTime = new int[length]; //完成时间int[] turnTime = new int[length]; //周转时间int[] rightTurnTime = new int[length]; //带权周转时间startTime[0] = requestTime[0];finishTime[0] = startTime[0] + durationTime[0];waitTime[0] = startTime[0] - requestTime[0];turnTime[0] = finishTime[0] - requestTime[0];rightTurnTime[0] = turnTime[0] / durationTime[0];int minIndex = 0;int lastIndex = 0;int[] durations = getMin( requestTime,serviceTime); //得到任务调动的顺序for(int i=1; i<length; i++){minIndex = durations[i-1]+1;startTime[minIndex] = finishTime[lastIndex]; //开始时间 = task == 0 ? 0 : 上个优选任务 完成时间 finishTime[minIndex] = startTime[minIndex] + durationTime[minIndex]; //完成时间 = 开始时间 + 服务时间waitTime[minIndex] = startTime[minIndex] - requestTime[minIndex]; //等待时间 = 开始时间 - 提交时间turnTime[minIndex] = finishTime[minIndex] - requestTime[minIndex]; //周转时间 = 完成时间 - 提交时间rightTurnTime[minIndex] = turnTime[minIndex] / durationTime[minIndex]; //带权周转时间 = 周转时间 / 服务时间lastIndex = minIndex; //将当前索引记为上一个任务索引}//打印System.out.println();prints("作业名:",task);prints("提交时间:",requestTime);prints("服务时间:",durationTime);prints("开始时间:",startTime);prints("完成时间:",finishTime);prints("等待时间:",waitTime);prints("周转时间:",turnTime);prints("带权周转时间:",rightTurnTime);int add = 0;float result; for(int i=0; i< length; i++){add += waitTime[i];}result = add/length; //求平均等待时间return result;}/** * 打印 * @param name * @param arr */private static void prints(String name, int[] arr) {System.out.print(name);for(int i=0 ; i<arr.length; i++){System.out.print(arr[i] + " ");}System.out.println();}/** * 得到任务调动的顺序 * @param requstTime * @param durationTime * @return */private static int[] getMin(int[] requstTime, int[] durationTime) {int length = durationTime.length;int[] arr = new int[length-1]; //去除第一个任务,剩下的任务的服务时间int[] arr1 = new int[length-1]; //存放剩下任务的开始顺序索引int[] arr2 = new int[length-1]; //存放剩下任务的开始顺序值for(int i=0; i<arr.length ; i++){arr[i] = durationTime[i+1];}int minIndex =0; for(int i=0; i<arr.length; i++){ //趟数for(int j=0 ; j<arr.length; j++){ //冒泡比较法,但是不交换位置if(arr[j] < arr[minIndex]){minIndex = j;}}arr1[i] = minIndex;arr2[i] = arr[minIndex];arr[minIndex] = Integer.MAX_VALUE;}/*//判断是否有任务服务时间相同的,再根据请求时间判断 * 其实有点多余,请求时间是按升序排序 * for(int k=0 ; k<arr2.length-1; k++){ if(arr2[k] == arr2[k+1]){if(requstTime[arr1[k]+1] > requstTime[arr1[k+1]+1]){int tmp = arr1[k];arr1[k] = arr1[k+1];arr1[k+1] = tmp;}}}*//*System.out.println("最大索引数组:");for(int i=0; i<arr1.length; i++){System.out.print(" " + arr1[i]);}System.out.println();*/return arr1;}public static void main(String[] args) {int[] requestTime = {0,2,4,5};int[] durationTime = {7, 4, 1, 4}; int[] a = new int[3];ShortJobFirst sjf = new ShortJobFirst();float averageWaitTime = sjf.minAgerageWaitTime(requestTime, durationTime);//a = sjf.getMin(requestTime, durationTime);System.out.println();System.out.println("平均等待时间:" + averageWaitTime );}}
总结:
代码实现该算法的核心在于调度切换时查找服务时间数组中的最小值,即最短作业,
getMin(int[] requstTime, int[] durationTime)
该方法返回该任务调度顺序的数组。具体详情请看代码。