模拟先来先服务、短作业优先、时间片轮转以及最高响应比优先调度算法的JAVA实现

这里记录一下操作系统的实验,几个调度算法的原理很好理解,网上也有很多解释,这里不再解释,直接上代码。

一、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
相关推荐
©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页