操作系统常见的进程调度算法

1.先来先服务

       (FCFS: first come first service)总是把当前处于就绪队列之首的那个进程调度到运行状态。也就说,它只考虑进程进入就绪队列的先后,而不考虑它的其他因素。FCFS算法简单易行,是一种非抢占式策略,但性能却不大好。只考虑他的到达时间来决定他的执行顺序。

private void FCFS() {

//        按提交时间排序得到新的序列
        float[] arr = new float[size];
        Processcourse[] tmp = new Processcourse[size];
        for (int i = 0; i < size ; i++) {
            arr[i] = work[i].submitTime;
        }
        Arrays.sort(arr);
        for (int i = 0; i < size ; i++) {
            for (int j = 0; j < size ; j++) {
                if(arr[i] == work[j].submitTime){
                    tmp[i] = work[j];
                }
            }
        }
        work = tmp;


        //得到第一个的任务的全部时间
        work[0].startTime = work[0].submitTime;
        work[0].finishTime = work[0].submitTime + work[0].runTime;
       //求出每个的开始时间和结束时间
        for (int j = 1; j < this.size; j++) {
            if(work[j].submitTime <= work[j-1].finishTime){//判断后面进程是否到来
            work[j].startTime = work[j-1].finishTime;
            work[j].finishTime = work[j].startTime+work[j].runTime;
            }else{
                work[j].startTime = work[j].submitTime;
                work[j].finishTime = work[j].startTime+work[j].runTime;
            }
        }
        //求出周转时间和带权周转时间
        for (int j = 0; j < this.size; j++) {
            work[j].turnoverTime = work[j].finishTime - work[j].submitTime;
            work[j].wtTime = work[j].turnoverTime/work[j].runTime;
        }
        System.out.println("运行顺序:");
        for (int i = 0; i < this.size; i++) {
            System.out.print(work[i].workName+" ");
        }
        System.out.println();
        System.out.println("作业"+"	"+"提交时间"+"	"+"运行时间"+"	"+"开始时间"+"	"+"结束/完成时间"+"	"+"周转时间"+"	"+"带权周转时间");
        for (int i = 0; i < this.size; i++) {
            //小数点后保留一位,并且四舍五入
            System.out.println(work[i].workName+"    "+work[i].submitTime+"      "+work[i].runTime+"      "+work[i].startTime+"      "
                    +work[i].finishTime+"      "+(float)(Math.round(work[i].turnoverTime*10))/10+"      "+(float)(Math.round(work[i].wtTime*10))/10);
        }

        float sumturnTime = 0;
        float sumwtfTime = 0;
        for (int i = 0; i < this.size; i++) {
            sumturnTime+= work[i].turnoverTime;
            sumwtfTime+= work[i].wtTime;
        }
        System.out.println("平均周转时间:"+(float)(Math.round((sumturnTime/size)*100))/100+" "+"平均带权周转时间:"+(float)(Math.round((sumwtfTime/size)*100))/100);

    }

  测试用例:

1  8.5  0.5  1
2  8.0  1.0  1
3  9.0  0.2  2
4  9.1  0.1  3

运行结果:

2.短作业优先

      (SJF, Shortest Job First),对预计执行时间短的作业(进程)优先分派处理机。 再不考虑抢占的前提下,判断进程到达时间是否小于上一个进程的完成时间,进入等待序列,然后找到等待序列的完成所要时间最短的进程。

    private void SJF() {

        //按提交时间排序得到新的序列
        float[] arr = new float[size];
        Processcourse[] tmpArr = new Processcourse[size];
        for (int i = 0; i < size ; i++) {
            arr[i] = work[i].submitTime;
        }
        //排序提交时间
        Arrays.sort(arr);
        //重新赋值
        for (int i = 0; i < size ; i++) {
            for (int j = 0; j < size ; j++) {
                if(arr[i] == work[j].submitTime){
                    tmpArr[i] = work[j];
                }
            }
        }
        work = tmpArr;

        //得到第一个的任务的开始时间和完成时间
        work[0].startTime = work[0].submitTime;
        work[0].finishTime = work[0].submitTime + work[0].runTime;

        //存入第一个进程完成时间
        float tmpfinshTime = work[0].finishTime;

        //等待序列
        Processcourse[] wait = new Processcourse[this.size];
        //运行完成序列
        Processcourse[] finish  = new Processcourse[this.size];
        int finNum = 0;//完成序列的个数
        int index = 1;//下标从数组的一号位置开始

        System.out.println("运行进程:");
        System.out.println(work[0].workName);
        for (int j = 0; j < size-1; j++) {
        int num = 0;   //等待
        int k = 1;

        //等待序列
          System.out.println("等待进程:");
        for (int i = 1; i < this.size; i++) {
            if(work[i]!=null && work[i].submitTime <= tmpfinshTime){
                wait[k] = work[i];
                k++;
                num++;
            }
        }
        //遍历等待序列
            for (int i = 1 ; i <= num; i++) {
                System.out.print(wait[i].workName+" ");
            }
            System.out.println();

        float min = 0.0f;
        //找到等待序列的最小运行时间
            min = wait[1].runTime;
        for (int i = 1; i <= num; i++) {
                if (wait[i].runTime < min) {
                    min = wait[i].runTime;
                }
        }
        for (int i = 1; i < size ; i++) {
            if(work[i] != null && work[i].runTime == min){
                work[i].startTime = tmpfinshTime;
                work[i].finishTime = work[i].startTime+work[i].runTime;
                //更新完成时间
                tmpfinshTime = work[i].finishTime;
                finish[index++] = work[i];
                finNum++;
                work[i] = null;
            }
        }

            //输出运行过的进程
            System.out.println("运行进程:");
            System.out.println(finish[finNum].workName);
    }

    //将临时值放回原数组
        for (int i = 1; i <= finNum; i++) {
            work[i] = finish[i];
        }
        

            //求出周转时间和带权周转时间
            for (int i = 0; i < this.size; i++) {
                work[i].turnoverTime = work[i].finishTime - work[i].submitTime;
                work[i].wtTime = work[i].turnoverTime / work[i].runTime;
            }

            System.out.println("作业" + "	" + "提交时间" + "	" + "运行时间" + "	" + "开始时间" + "	" + "结束/完成时间" + "	" + "周转时间" + "	" + "带权周转时间");
            for (int i = 0; i < this.size; i++) {
                //小数点后保留一位,并且四舍五入
                System.out.println(work[i].workName + "    " + work[i].submitTime + "      " + work[i].runTime + "      " + work[i].startTime + "      "
                        + work[i].finishTime + "      " + (float) (Math.round(work[i].turnoverTime * 10)) / 10 + "      " + (float) (Math.round(work[i].wtTime * 10)) / 10);
            }
        float sumturnTime = 0;
        float sumwtfTime = 0;
        for (int i = 0; i < this.size; i++) {
            sumturnTime+= work[i].turnoverTime;
            sumwtfTime+= work[i].wtTime;
        }
        System.out.println("平均周转时间:"+(float)(Math.round((sumturnTime/size)*100))/100+"  "+"平均带权周转时间:"+(float)(Math.round((sumwtfTime/size)*100))/100);
        }

测试用例:

1  8.5  0.5  1
2  8.0  1.0  1
3  9.0  0.2  2
4  9.1  0.1  3

运行结果:

3.高响应比优先

       高响应比优先调度算法(Highest Response Ratio Next)是一种对CPU中央控制器响应比的分配的一种算法。HRRN是介于FCFS(先来先服务算法)与SJF(短作业优先算法)之间的折中算法,既考虑作业等待时间又考虑作业运行时间,既照顾短作业又不使长作业等待时间过长,改进了调度性能。

       响应比 =(等待时间+要求服务时间)/ 要求服务时间

private void HRRN() {
        //按提交时间排序得到新的序列
        float[] arr = new float[size];
        Processcourse[] tmpArr = new Processcourse[size];
        for (int i = 0; i < size; i++) {
            arr[i] = work[i].submitTime;
        }
        //排序提交时间
        Arrays.sort(arr);
        //重新赋值
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (arr[i] == work[j].submitTime) {
                    tmpArr[i] = work[j];
                }
            }
        }
        work = tmpArr;

        //得到第一个的任务的开始时间和完成时间
        work[0].startTime = work[0].submitTime;
        work[0].finishTime = work[0].submitTime + work[0].runTime;

        //存入第一个进程完成时间
        float tmpfinshTime = work[0].finishTime;

        //等待序列
        Processcourse[] wait = new Processcourse[this.size];
        //运行完成序列
        Processcourse[] finish = new Processcourse[this.size];
        int finNum = 0;//等待序列的个数
        int index = 1;//下标从数组的一号位置开始

        System.out.println("运行顺序如下:");
        System.out.println("运行进程:");
        System.out.println(work[0].workName);

        //运行的次数
        for (int j = 1; j < size; j++) {
            int num = 0;
            int k = 1;

            //等待序列
            System.out.println("等待进程:");
            for (int i = 1; i < this.size; i++) {
                if (work[i] != null && work[i].submitTime <= tmpfinshTime) {
                    wait[k] = work[i];
                    k++;
                    num++;
                }
            }
            //遍历等待序列
            for (int i = 1; i <= num; i++) {
                System.out.print(wait[i].workName + " ");
            }
            System.out.println();

            //找到等待序列的最高优先级
            float max = 0.0f;
            float waitTime = 0.0f;
            float tmp2 = 0.0f;//记录响应比
//            Processcourse[] tmp1 = new Processcourse[this.size];
            String tmpName = null;
            for (int i = 1; i <= num; i++) {
                waitTime =tmpfinshTime - wait[i].submitTime;
                tmp2 = 1.0F+(waitTime/wait[i].runTime);
                wait[i].priority = tmp2;
                max = (1.0f+((tmpfinshTime - wait[1].submitTime)/wait[1].runTime));
                if(tmp2 > max){
                   max = (1.0f+(waitTime/wait[i].runTime));
                    tmpName = wait[i].workName;
                }else {
                    tmpName = wait[1].workName;
                }
            }



            for (int i = 1; i < this.size; i++) {
                if(work[i] != null && tmpName.equals(work[i].workName)){
                    work[i].priority = max;
                }
            }
        //tmp1置空
//            tmp1 = null;
            for (int i = 1; i < size; i++) {
                if (work[i] != null && work[i].priority == max) {
                    work[i].startTime = tmpfinshTime;
                    work[i].finishTime = work[i].startTime + work[i].runTime;
                    //更新完成时间
                    tmpfinshTime = work[i].finishTime;
                    //更新
                    finish[index++] = work[i];
                    finNum++;
                    work[i] = null;
                }
            }

            //输出运行过的进程
            System.out.println("运行进程:");
            System.out.println(finish[finNum].workName);
        }

        //将临时值放回原数组
        for (int i = 1; i <= finNum; i++) {
            work[i] = finish[i];
        }
        

        //求出周转时间和带权周转时间
        for (int i = 0; i < this.size; i++) {
            work[i].turnoverTime = work[i].finishTime - work[i].submitTime;
            work[i].wtTime = work[i].turnoverTime / work[i].runTime;
        }

        System.out.println("作业" + "	" + "提交时间" + "	" + "运行时间" + "	" + "开始时间" + "	" + "结束/完成时间" + "	" + "周转时间" + "	" + "带权周转时间"+"	"+"响应比");
        for (int i = 0; i < this.size; i++) {
            //小数点后保留一位,并且四舍五入
            System.out.println(work[i].workName + "    " + work[i].submitTime + "      " + work[i].runTime + "      " + work[i].startTime + "      "
                    + work[i].finishTime + "      " + (float) (Math.round(work[i].turnoverTime * 100)) / 100 + "      " + (float) (Math.round(work[i].wtTime * 100)) / 100+"     "+(float) (Math.round(work[i].priority* 100)) / 100);
        }
        float sumturnTime = 0;
        float sumwtfTime = 0;
        for (int i = 0; i < this.size; i++) {
            sumturnTime += work[i].turnoverTime;
            sumwtfTime += work[i].wtTime;
        }
        System.out.println("平均周转时间:" + (float) (Math.round((sumturnTime / size) * 100)) / 100 + "  " + "平均带权周转时间:" + (float) (Math.round((sumwtfTime / size) * 100)) / 100);
    }

测试用例:

1  8.5  0.5  1
2  8.0  1.0  1
3  9.0  0.2  2
4  9.1  0.1  3

运行结果:

4.时间片轮转法

    时间片轮转(RR)是一种最古老,最简单,最公平且使用最广的算法。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。

    private void RR() {
        System.out.println("请输入时间片的大小:");
        float fTime = sc.nextFloat();//时间片大小
        if(fTime <= 0 ){
            System.out.println("无效输入");
            return;
        }

        //按提交时间排序得到新的序列
        float[] arr = new float[size];
        Processcourse[] tmpArr = new Processcourse[size];
        for (int i = 0; i < size; i++) {
            arr[i] = work[i].submitTime;
        }
        //排序提交时间
        Arrays.sort(arr);
        //重新赋值
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (arr[i] == work[j].submitTime) {
                    tmpArr[i] = work[j];
                }
            }
        }
        work = tmpArr;
        //方便再次调用
        for (int i = 0; i < this.size; i++) {
            work[i].flag = false;
        }
        //无该过程最终运行时间全为0.0(最终重新赋值给work)
        float tempRunTime[] = new float[this.size];
        for (int i = 0; i < this.size; i++) {
            tempRunTime[i] = work[i].runTime;
        }

        //等待序列
        Processcourse[] wait = new Processcourse[100];
        int num = 1;   //等待序列个数(开始默认一个)

        //运行完成序列
        Processcourse[] finish  = new Processcourse[this.size];
        int number = 0;  //完成个数
        //当前切换的时间
        float nowTime = work[0].submitTime;  //记录进程开始时间
        float overTime = 0;  //记录进程出来时间

        wait[0] = work[0];
        work[0].flag = true;//标记其已经进入等待序列(false么有进入过,true进入过,相当于原数组的元素只进入一次就绪队列,接下来的的其结束与否只在等待序列中判断)
        String tmpName = null;

        //临时记录在上一个么有完成的进程
        Processcourse[] tmpWait = new Processcourse[1];

        System.out.println("时刻:"+nowTime+" 进程:"+work[0].workName+" 开始运行");
        int k= 0;
        int stopFlag = 0;
        //当作业么有运行完,一直执行
        while (stopFlag != this.size){
            //当前任务么有运行完
            if(wait[k]!=null) {
                if (wait[k].runTime > fTime) {
                    wait[k].runTime -= fTime;
                    //更新当前还需要运行的时间
                    nowTime += fTime;//更新当前时间
                    System.out.println("时刻:" + nowTime + " 进程:" + wait[k].workName + " 停止运行,进入就绪队列");
                    tmpWait[0] = wait[k];
                } else {
                    nowTime += wait[k].runTime;
                    wait[k].runTime = 0;//说明运行结束
                    tmpName = wait[k].workName;
                    overTime = nowTime;
                    System.out.println("时刻:" + overTime + " 进程:" + wait[k].workName + " 运行结束");
                }
            }
            //如果等待序列里面其运行结束,将原数组直null,方便不去判断,并且完成数加一
            for (int j = 0; j < this.size; j++) {
                if(work[j] != null && tmpName!= null && tmpName.equals(work[j].workName)){//让运行过得不能排在么运行的前面
                    work[j].finishTime = overTime;
//                    work[j].turnoverTime = overTime - work[j].submitTime;
//                    work[j].wtTime = (work[j].turnoverTime/work[j].runTime);
                    finish[number++] = work[j];
                    work[j] = null;
                    stopFlag++;
                }
            }

            //判断进入等待序列
            for (int j = 0; j < this.size; j++) {
                if((work[j] != null)  && (work[j].submitTime <= nowTime) && (work[j].flag == false) ){
                    wait[num++] = work[j];
                    work[j].flag = true;
                }
            }

            if(tmpWait[0] != null) {
                wait[num++] = tmpWait[0];
            }
                tmpWait[0] = null;
            k++;

        }

       wait = null;
        //将其放回原work数组
        for (int i = 0; i < this.size; i++) {
            work[i] = finish[i];
        }

        //按提交时间排序得到新的序列
        float[] arr1 = new float[size];
        Processcourse[] tmpArr1 = new Processcourse[size];
        for (int i = 0; i < size; i++) {
            arr1[i] = work[i].submitTime;
        }
        //排序提交时间
        Arrays.sort(arr1);
        //重新赋值
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (arr1[i] == work[j].submitTime) {
                    tmpArr1[i] = work[j];
                }
            }
        }
        work = tmpArr1;

        //还原其初始运行时间
        for (int i = 0; i < this.size ; i++) {
            work[i].runTime = tempRunTime[i];
        }

        //求出周转时间和带权周转时间
        for (int i = 0; i < this.size; i++) {
            work[i].turnoverTime = work[i].finishTime - work[i].submitTime;
            work[i].wtTime = work[i].turnoverTime / work[i].runTime;
        }

        System.out.println("作业" + "	" + "提交时间" + "	" + "运行时间" +  "	" + "结束/完成时间" + "	" + "周转时间" + "	" + "带权周转时间");
        for (int i = 0; i < this.size; i++) {
            //小数点后保留一位,并且四舍五入
            System.out.println(work[i].workName + "    " + work[i].submitTime + "      " + work[i].runTime +  "      "
                    + work[i].finishTime + "      " + (float) (Math.round(work[i].turnoverTime * 100)) / 100 + "      " + (float) (Math.round(work[i].wtTime * 100)) / 100);
        }
        float sumturnTime = 0;
        float sumwtfTime = 0;
        for (int i = 0; i < this.size; i++) {
            sumturnTime += work[i].turnoverTime;
            sumwtfTime += work[i].wtTime;
        }
        System.out.println("平均周转时间:" + (float) (Math.round((sumturnTime / size) * 100)) / 100 + "  " + "平均带权周转时间:" + (float) (Math.round((sumwtfTime / size) * 100)) / 100);

    }

测试用例:

p1  0  5  1
p2  2  4  1
p3  4  1  1
p4  5  6  1

运行结果:

进程类:

public class Processcourse {
    String workName;//作业
    float submitTime; //提交时间
    float runTime;//运行时间
    float startTime;//开始时间
    float finishTime;  //完成时间
    float turnoverTime;//周转时间
    float wtTime;   //带权周转时间
    float priority;  //响应比
    float prior;     //优先级
    boolean flag;   //标记

    public Processcourse(String work, float submitTime, float runTime,float prior) {
        this.workName = work;
        this.submitTime = submitTime;
        this.runTime = runTime;
        this.prior = prior;
    }

    @Override
    public String toString() {
        return "Processcourse{" +
                "workName=" + workName +
                ", submitTime=" + submitTime +
                ", runTime=" + runTime +
                ", startTime=" + startTime +
                ", finishTime=" + finishTime +
                ", turnoverTime=" + turnoverTime +
                ", wtTime=" + wtTime +
                ",priority=" + priority+
                "prior="+prior+
                ",flag="+flag+
                '}';
    }

}

初始化以及main函数类:

public class Control {
    private Processcourse[] work;
    int maxWork = 100;
    int size; //真实作业个数
    private Scanner sc;
    public Control() {
      this.work = new Processcourse[maxWork];
      this.sc = new Scanner(System.in);
    }

    public static void main(String[] args) {
        Control con = new Control();
        con.start();//程序入口
    }

    private void start() {
        System.out.println("===================================");
        System.out.println("欢迎来到本系统");
        //初始化
        System.out.println("请输入进程的个数:" );
        int num = sc.nextInt();
        System.out.println("请依次输入进程号,提交时间,运行时间,优先级(中间用空格隔开):");
        int i = 0;
        while(i < num){
            String workName = sc.next();//作业名
            float submitTime = sc.nextFloat(); //提交时间
            float runTime = sc.nextFloat();//运行时间
            float  prior = sc.nextFloat();//优先级
            if(i == size){
                this.work[this.size++] = new Processcourse(workName,submitTime,runTime,prior);
            }
            i++;
        }
        for (; ; ) {
            System.out.println("请选择进程调度方法:");
            System.out.println("1.先来先服务法");
            System.out.println("2.短作业优先法");
            System.out.println("3.高响应比法");
            System.out.println("4.时间片轮转法");
            System.out.println("5.高优先级法");
            System.out.println("6.退出");
            System.out.println("===================================");
            int ch = sc.nextInt();
            switch (ch){
                case 1:
                    FCFS();
                    break;
                case 2:
                    SJF();
                    break;
                case 3:
                    HRRN();
                    break;
                case 4:
                    RR();
                    break;
                case 5:
                    PSA();
                    break;
                case 6:
                    System.out.println("再见");
                    return;
                    default:
                        System.out.println("无效输入,请重新输入!");
            }
        }
    }

        以上便是除了高优先级的(高优先级同短作业优先代码类似)全部代码,由于采用数组代码比较冗长,输出函数可以单独写一个方法封装,也可以减少代码量,但是由于当时图方便,直接将第一个写的粘贴修改输出,自己可以将其封装。

  

原文地址:https://www.cnblogs.com/128-cdy/p/12187875.html