这里记录一下操作系统的实验,几个调度算法的原理很好理解,网上也有很多解释,这里不再解释,直接上代码。
一、JCB类
public class JCB {
public int id;
/**
* 剩余服务时间
*/
public int leftTime;
/**
* 要求服务时间
*/
public int serviceTime;
/**
* 到达时间
*/
public int arriveTime;
/**
* 开始时间
*/
public int beginTime;
/**
* 结束时间
*/
public int finishTime;
/**
* 优先权
*/
public float priority;
public JCB(int id, int serviceTime, int arriveTime,float priority) {
this.id = id;
this.leftTime = serviceTime;
this.serviceTime = serviceTime;
this.arriveTime = arriveTime;
beginTime =0;
this.priority=priority;
finishTime=0;
}
@Override
public String toString() {
return "JCB{" +
"id=" + id +
", serviceTime=" + serviceTime +
", arriveTime=" + arriveTime +
", priority=" + priority +
'}';
}
}
二、定义所需数据结构
/**
* 时间片轮转算法
*
* @author MaoLin Wang
* @date 2019/11/3020:03
*/
public class SchedulingAlgorithm {
/**
* 就绪队列
*/
LinkedList<JCB> readyQueue = null;
/**
* 结束调度队列
*/
LinkedList<JCB> finishQueue = null;
/**
* 时间段
*/
private int cpuTime;
/**
* 时间片大小
*/
private int timeSize;
/**
* 作业数
*/
private int jobNum;
private String dispatchName;//调度算法名
/**
* 作业周转时间
*/
private int[] turnoverTime;
/**
* 作业带权周转时间·
*/
private float[] turnoverTimeWithWeight;
/**
* 平均带权周转时间
*/
private float ave;
}
三、初始化
这里将最高响应比的初始化拉了出来,因为要设置响应比
/**
* 初始化
*/
public void init(int jobNum, int timeSize, String dispatchName) {
System.out.println("开始" + dispatchName + "调度");
readyQueue = new LinkedList<>();
finishQueue = new LinkedList<>();
this.turnoverTime = new int[jobNum];
this.turnoverTimeWithWeight = new float[jobNum];
this.cpuTime = 0;
JCB jcb;
for (int i = 1; i <= jobNum; i++) {
jcb = new JCB(i, (int) (Math.random() * 10 + 1), i - 1, 0);
readyQueue.offer(jcb);
}
this.timeSize = timeSize;
this.jobNum = jobNum;
this.dispatchName = dispatchName;
printInitQueue();
}
/**
* 初始化高响应比优先队列
*
* @param jobNum
* @param timeSize
* @param dispatchName
*/
public void HRNInit(int jobNum, int timeSize, String dispatchName) {
System.out.println("开始" + dispatchName + "调度");
readyQueue = new LinkedList<>();
finishQueue = new LinkedList<>();
this.turnoverTime = new int[jobNum];
this.turnoverTimeWithWeight = new float[jobNum];
this.cpuTime = 0;
JCB jcb;
for (int i = 1; i <= jobNum; i++) {
float v = (float) (Math.random() * 5 + 1);
jcb = new JCB(i, (int) (Math.random() * 10 + 1), i - 1, (float) (Math.random() * 5 + 1));
readyQueue.offer(jcb);
}
this.timeSize = timeSize;
this.jobNum = jobNum;
this.dispatchName = dispatchName;
printInitQueue();
}
作业id默认为序号i,所需服务时间随机生成,到达时间默认从0开始,响应比其他调度算法为0,高响应比算法为随机生成。
四、高响应比优先算法实现
逻辑很简单,使用递归实现,参数初始为0,每次取出对头作业,因为这里所有的作业在初始化时数据都初始化好了,所以需判断作业到达时间是否小于cpu时间片,因为只有小于时间片,说明其实际是到达的。
如果小于,则设置其开始时间为cpu当前时间,结束时间为开始时间+服务时间,剩余时间设为0,同时增加cpu时间,将该作业加入已完成队列中,否则,递归调用该算法,参数为index+1,一轮结束后,对作业按响应比排序,继续递归,知道就绪队列为空。
/**
* 最高响应比优先算法
*/
public void HRNAlgorithm(int index) {
if (readyQueue.size() == 0) {
System.out.println("就绪队列为空,调度完毕!");
return;
}
JCB head = readyQueue.get(index);
if (head.arriveTime <= cpuTime) {
readyQueue.poll();
System.out.println("-----------------------------------------------------");
System.out.println("时间片: " + cpuTime + "开始调度作业:" + head.id + ", 剩余服务时间: " + head.leftTime);
head.beginTime = cpuTime;
head.finishTime = head.beginTime + head.serviceTime;
head.leftTime = 0;
cpuTime += head.serviceTime;
finishQueue.offer(head);
System.out.println("时间片: " + cpuTime + "结束调度作业:" + head.id + ", 剩余服务时间: " + head.leftTime);
} else {
HRNAlgorithm(index++);
}
sortByPriority();
HRNAlgorithm(0);
}
/**
* 根据响应比排序
*/
private void sortByPriority() {
readyQueue.sort((o1, o2) -> o1.priority > o2.priority ? -1 : 1);
}
五、短作业优先调度算法
同高响应比优先类似,只是按照要求服务时间排序。
/**
* 短作业优先调度算法
*/
public void SJFAlgorithm(int index) {
if (readyQueue.size() == 0) {
System.out.println("就绪队列为空,调度完毕!");
return;
}
JCB head = readyQueue.get(index);
if (head.arriveTime <= cpuTime) {
readyQueue.poll();
System.out.println("-----------------------------------------------------");
System.out.println("时间片: " + cpuTime + "开始调度作业:" + head.id + ", 剩余服务时间: " + head.leftTime);
head.beginTime = cpuTime;
head.finishTime = head.beginTime + head.serviceTime;
head.leftTime = 0;
cpuTime += head.serviceTime;
finishQueue.offer(head);
System.out.println("时间片: " + cpuTime + "结束调度作业:" + head.id + ", 剩余服务时间: " + head.leftTime);
} else {
sortByServiceTime();
SJFAlgorithm(index++);
}
sortByServiceTime();
SJFAlgorithm(0);
}
/**
* 根据要求服务时间从小到大排序
*/
private void sortByServiceTime() {
readyQueue.sort((o1, o2) -> o1.serviceTime < o2.serviceTime ? -1 : 1);
}
六、先来先服务
最简单的一个算法,直接按顺序取出队头作业执行。
/**
* 先来先服务调度算法
*/
public void FCFSAlgorithm() {
if (readyQueue.size() == 0) {
System.out.println("就绪队列为空,调度完毕!");
return;
}
JCB head = readyQueue.poll();
System.out.println("-----------------------------------------------------");
System.out.println("时间片: " + cpuTime + "开始调度作业:" + head.id + ", 剩余服务时间: " + head.leftTime);
head.beginTime = cpuTime;
head.leftTime = 0;
head.finishTime = head.beginTime + head.serviceTime;
cpuTime += head.serviceTime;
finishQueue.offer(head);
System.out.println("时间片: " + cpuTime + "结束调度作业:" + head.id + ", 剩余服务时间: " + head.leftTime);
FCFSAlgorithm();
}
七、时间片轮转算法
这里需要根据作业剩余需要服务的时间跟时间片大小做对比,代码很好理解。
/**
* 时间片轮转算法
*/
public void RRAlgorithm() {
if (readyQueue.size() == 0) {
System.out.println("就绪队列为空,调度完毕!");
return;
}
JCB head = readyQueue.poll();
System.out.println("-----------------------------------------------------");
System.out.println("时间片: " + cpuTime + "开始调度作业:" + head.id + ", 剩余服务时间: " + head.leftTime);
head.beginTime = cpuTime;
if (head.leftTime > timeSize) {
//服务时间大于时间片大小
head.leftTime -= timeSize;
//重新加入到就绪队列尾部
readyQueue.offer(head);
cpuTime += timeSize;
} else if (head.leftTime == timeSize) {
//服务时间等于时间片大小
cpuTime += timeSize;
head.finishTime = cpuTime;
head.leftTime = 0;
//加入结束队列
finishQueue.offer(head);
} else {
//服务时间小于时间片大小
head.finishTime = cpuTime + head.leftTime;
head.leftTime = 0;
cpuTime += head.leftTime;
finishQueue.offer(head);
}
System.out.println("时间片: " + cpuTime + "结束调度作业:" + head.id + ", 剩余服务时间: " + head.leftTime);
RRAlgorithm();
}
八、计算周转时间和带权周转时间
/**
* 计算周转时间和带权周转时间
* @param finishQueue
*/
public void R_Dis(Queue<JCB> finishQueue) {
Queue<JCB>temp=finishQueue;
JCB tempJcb;
float sum = 0;
for (int i = 0; i < jobNum; i++) {
tempJcb=temp.poll();
turnoverTime[i] = tempJcb.finishTime - tempJcb.arriveTime;
turnoverTimeWithWeight[i] =(float) turnoverTime[i] / tempJcb.serviceTime;
sum += turnoverTimeWithWeight[i];
temp.offer(tempJcb);
}
float ave = sum / jobNum;
this.ave = ave;
}
九、打印结果
public void printResult(boolean isHRN) {
R_Dis(this.finishQueue);
System.out.println("=====================" + this.dispatchName + "调度结果为=========================");
if (isHRN) {
System.out.println("进程名\t" + "到达时间\t" + "要求服务时间\t" + "响应比\t" + "开始时间\t" + "完成时间\t" + "周转时间\t" + "带权周转时间\t"+"平均带权周转时间\t");
} else {
System.out.println("进程名\t" + "到达时间\t" + "要求服务时间\t" + "开始时间\t" + "完成时间\t" + "周转时间\t" + "带权周转时间\t"+"平均带权周转时间\t");
}
int count = 0;
for (JCB jcb : this.finishQueue) {
if (isHRN) {
System.out.println(" " + jcb.id + "\t\t\t" + jcb.arriveTime + "\t\t" + jcb.serviceTime + "\t\t" + jcb.priority + "\t\t" + jcb.beginTime + "\t\t"
+ jcb.finishTime + "\t\t" + turnoverTime[count] + "\t\t" + turnoverTimeWithWeight[count]+"\t\t"+this.ave);
count = count + 1;
} else {
System.out.println(" " + jcb.id + "\t\t\t" + jcb.arriveTime + "\t\t" + jcb.serviceTime + "\t\t" + jcb.beginTime + "\t\t"
+ jcb.finishTime + "\t\t" + turnoverTime[count] + "\t\t" + turnoverTimeWithWeight[count]+"\t\t"+this.ave);
count = count + 1;
}
}
}
/**
* 打印初始化队列
*/
private void printInitQueue() {
System.out.println("当前就绪队列为:");
for (JCB jcb2 : readyQueue) {
System.out.println(jcb2);
}
}
测试
public class Test {
public static void main(String[] args) {
SchedulingAlgorithm schedulingAlgorithm = new SchedulingAlgorithm();
schedulingAlgorithm.init(5, 2,"轮转");
schedulingAlgorithm.RRAlgorithm();
schedulingAlgorithm.printResult(false);
schedulingAlgorithm.init(5,3,"先来先服务");
schedulingAlgorithm.FCFSAlgorithm();
schedulingAlgorithm.printResult(false);
schedulingAlgorithm.init(5,3,"短作业优先服务");
schedulingAlgorithm.SJFAlgorithm(0);
schedulingAlgorithm.printResult(false);
schedulingAlgorithm.HRNInit(5,3,"高响应比优先");
schedulingAlgorithm.HRNAlgorithm(0);
schedulingAlgorithm.printResult(true);
}
}
结果:
开始轮转调度
当前就绪队列为:
JCB{id=1, serviceTime=1, arriveTime=0, priority=0.0}
JCB{id=2, serviceTime=5, arriveTime=1, priority=0.0}
JCB{id=3, serviceTime=4, arriveTime=2, priority=0.0}
JCB{id=4, serviceTime=6, arriveTime=3, priority=0.0}
JCB{id=5, serviceTime=6, arriveTime=4, priority=0.0}
-----------------------------------------------------
时间片: 0开始调度作业:1, 剩余服务时间: 1
时间片: 0结束调度作业:1, 剩余服务时间: 0
-----------------------------------------------------
时间片: 0开始调度作业:2, 剩余服务时间: 5
时间片: 2结束调度作业:2, 剩余服务时间: 3
-----------------------------------------------------
时间片: 2开始调度作业:3, 剩余服务时间: 4
时间片: 4结束调度作业:3, 剩余服务时间: 2
-----------------------------------------------------
时间片: 4开始调度作业:4, 剩余服务时间: 6
时间片: 6结束调度作业:4, 剩余服务时间: 4
-----------------------------------------------------
时间片: 6开始调度作业:5, 剩余服务时间: 6
时间片: 8结束调度作业:5, 剩余服务时间: 4
-----------------------------------------------------
时间片: 8开始调度作业:2, 剩余服务时间: 3
时间片: 10结束调度作业:2, 剩余服务时间: 1
-----------------------------------------------------
时间片: 10开始调度作业:3, 剩余服务时间: 2
时间片: 12结束调度作业:3, 剩余服务时间: 0
-----------------------------------------------------
时间片: 12开始调度作业:4, 剩余服务时间: 4
时间片: 14结束调度作业:4, 剩余服务时间: 2
-----------------------------------------------------
时间片: 14开始调度作业:5, 剩余服务时间: 4
时间片: 16结束调度作业:5, 剩余服务时间: 2
-----------------------------------------------------
时间片: 16开始调度作业:2, 剩余服务时间: 1
时间片: 16结束调度作业:2, 剩余服务时间: 0
-----------------------------------------------------
时间片: 16开始调度作业:4, 剩余服务时间: 2
时间片: 18结束调度作业:4, 剩余服务时间: 0
-----------------------------------------------------
时间片: 18开始调度作业:5, 剩余服务时间: 2
时间片: 20结束调度作业:5, 剩余服务时间: 0
就绪队列为空,调度完毕!
=====================轮转调度结果为=========================
进程名 到达时间 要求服务时间 开始时间 完成时间 周转时间 带权周转时间 平均带权周转时间
1 0 1 0 1 1 1.0 2.3733335
3 2 4 10 12 10 2.5 2.3733335
2 1 5 16 17 16 3.2 2.3733335
4 3 6 16 18 15 2.5 2.3733335
5 4 6 18 20 16 2.6666667 2.3733335
开始先来先服务调度
当前就绪队列为:
JCB{id=1, serviceTime=3, arriveTime=0, priority=0.0}
JCB{id=2, serviceTime=10, arriveTime=1, priority=0.0}
JCB{id=3, serviceTime=7, arriveTime=2, priority=0.0}
JCB{id=4, serviceTime=1, arriveTime=3, priority=0.0}
JCB{id=5, serviceTime=1, arriveTime=4, priority=0.0}
-----------------------------------------------------
时间片: 0开始调度作业:1, 剩余服务时间: 3
时间片: 3结束调度作业:1, 剩余服务时间: 0
-----------------------------------------------------
时间片: 3开始调度作业:2, 剩余服务时间: 10
时间片: 13结束调度作业:2, 剩余服务时间: 0
-----------------------------------------------------
时间片: 13开始调度作业:3, 剩余服务时间: 7
时间片: 20结束调度作业:3, 剩余服务时间: 0
-----------------------------------------------------
时间片: 20开始调度作业:4, 剩余服务时间: 1
时间片: 21结束调度作业:4, 剩余服务时间: 0
-----------------------------------------------------
时间片: 21开始调度作业:5, 剩余服务时间: 1
时间片: 22结束调度作业:5, 剩余服务时间: 0
就绪队列为空,调度完毕!
=====================先来先服务调度结果为=========================
进程名 到达时间 要求服务时间 开始时间 完成时间 周转时间 带权周转时间 平均带权周转时间
1 0 3 0 3 3 1.0 8.154286
2 1 10 3 13 12 1.2 8.154286
3 2 7 13 20 18 2.5714285 8.154286
4 3 1 20 21 18 18.0 8.154286
5 4 1 21 22 18 18.0 8.154286
开始短作业优先服务调度
当前就绪队列为:
JCB{id=1, serviceTime=8, arriveTime=0, priority=0.0}
JCB{id=2, serviceTime=10, arriveTime=1, priority=0.0}
JCB{id=3, serviceTime=1, arriveTime=2, priority=0.0}
JCB{id=4, serviceTime=10, arriveTime=3, priority=0.0}
JCB{id=5, serviceTime=1, arriveTime=4, priority=0.0}
-----------------------------------------------------
时间片: 0开始调度作业:1, 剩余服务时间: 8
时间片: 8结束调度作业:1, 剩余服务时间: 0
-----------------------------------------------------
时间片: 8开始调度作业:3, 剩余服务时间: 1
时间片: 9结束调度作业:3, 剩余服务时间: 0
-----------------------------------------------------
时间片: 9开始调度作业:5, 剩余服务时间: 1
时间片: 10结束调度作业:5, 剩余服务时间: 0
-----------------------------------------------------
时间片: 10开始调度作业:2, 剩余服务时间: 10
时间片: 20结束调度作业:2, 剩余服务时间: 0
-----------------------------------------------------
时间片: 20开始调度作业:4, 剩余服务时间: 10
时间片: 30结束调度作业:4, 剩余服务时间: 0
就绪队列为空,调度完毕!
=====================短作业优先服务调度结果为=========================
进程名 到达时间 要求服务时间 开始时间 完成时间 周转时间 带权周转时间 平均带权周转时间
1 0 8 0 8 8 1.0 3.72
3 2 1 8 9 7 7.0 3.72
5 4 1 9 10 6 6.0 3.72
2 1 10 10 20 19 1.9 3.72
4 3 10 20 30 27 2.7 3.72
开始高响应比优先调度
当前就绪队列为:
JCB{id=1, serviceTime=1, arriveTime=0, priority=5.41018}
JCB{id=2, serviceTime=6, arriveTime=1, priority=5.1338425}
JCB{id=3, serviceTime=6, arriveTime=2, priority=3.1670618}
JCB{id=4, serviceTime=6, arriveTime=3, priority=2.0463989}
JCB{id=5, serviceTime=1, arriveTime=4, priority=4.711568}
-----------------------------------------------------
时间片: 0开始调度作业:1, 剩余服务时间: 1
时间片: 1结束调度作业:1, 剩余服务时间: 0
-----------------------------------------------------
时间片: 1开始调度作业:2, 剩余服务时间: 6
时间片: 7结束调度作业:2, 剩余服务时间: 0
-----------------------------------------------------
时间片: 7开始调度作业:5, 剩余服务时间: 1
时间片: 8结束调度作业:5, 剩余服务时间: 0
-----------------------------------------------------
时间片: 8开始调度作业:3, 剩余服务时间: 6
时间片: 14结束调度作业:3, 剩余服务时间: 0
-----------------------------------------------------
时间片: 14开始调度作业:4, 剩余服务时间: 6
时间片: 20结束调度作业:4, 剩余服务时间: 0
就绪队列为空,调度完毕!
=====================高响应比优先调度结果为=========================
进程名 到达时间 要求服务时间 响应比 开始时间 完成时间 周转时间 带权周转时间 平均带权周转时间
1 0 1 5.41018 0 1 1 1.0 2.1666665
2 1 6 5.1338425 1 7 6 1.0 2.1666665
5 4 1 4.711568 7 8 4 4.0 2.1666665
3 2 6 3.1670618 8 14 12 2.0 2.1666665
4 3 6 2.0463989 14 20 17 2.8333333 2.1666665