动态优先级算法(java实现)

算法导入

最近在学操作系统,老师的第一个实验要求——实现动态优先级进程调度算法。在度娘上也搜到了些,借鉴了一位大佬的设计思想,用java实现了简单的一个进程调度算法。

实验要求

1. 采用最高优先数的调度算法(即把处理机分配给优先数最高的进程)。
数字越小,优先级越高,当然我偷懒都设为正整数,你好我好大家好!

2. 每个进程有一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等等。

3. 进程信息可以手动输入也可以用随机数产生。

4. 每个进程的状态可以是就绪W(Wait)、运行R(Run)、或完成F(Finish)三种状态之一。

5. 就绪进程获得CPU后都只能运行一个时间片。用已占用CPU时间加1表示。

实验流程图

实验流程图

算法分析

对于这个模拟动态优先级的算法来说,可以用不同的语言来实现,比如C/C++,而网上用前面算法来执行的也占多数,但因为在学java,算了,就用java写这个算法吧,类的设计思想借鉴了一位大佬的算法,以前确实没写过,在此感谢,但是我忘了他的博客,下次找到了告诉你们(hhh)。

算法设计

1. 根据实验要求2,因为要存储进程的相关信息,那么首先应该做的就是设计一个Pcb类,不然到时候连进程的信息都无法获取,那就凉了。(知道你们喜欢代码,诺,直接上了)。哦对了,设计相关属性的时候,不要忘了get()和set()方法,要对值进行访问,这是必不可少的,虽然开发环境会自动产生属性的对应get方法和set方法,但是养成好习惯不好吗?

Pcb.java

/**
 * @author GoldenRetriever
 */
public class Pcb {
    /**
     *  进程名
     */
    private String pcbName;
    /**
     * 进程优先级
     */
    private int priority;

    /**
     *  进程到达时间
     */
    private int pcbArrivalTime;
    /**
     * 进程需要运行时间
     */
    private int pcbNeedRunningTime;
    /**
     * 进程已用CPU时间
     */
    private int pcbHasUsedTime = 0 ;
    /**
     * 进程状态 W(wait等待),R(run运行),F(finish完成)
     */
    private String pcbState = "Wait";

    /**
     * get and set
     */
    public String getPcbName() { 
        return pcbName; 
    }
    public void setPcbName(String pcbName) {
        this.pcbName = pcbName;
    }
    public int getPriority(){
        return priority;
    }
    public void setPriority(int priority) {
        this.priority = priority;
    }
    public int getPcbArrivalTime() {
        return pcbArrivalTime;
    }
    public void setPcbArrivalTime(int pcbArrivalTime) {
        this.pcbArrivalTime = pcbArrivalTime;
    }
    public int getPcbNeedRunningTime() { 
        return pcbNeedRunningTime;
    }
    public void setPcbNeedRunningTime(int needRunningTime) { 
        this.pcbNeedRunningTime = needRunningTime;
    }
    public int getPcbHasUsedTime() { 
        return pcbHasUsedTime; 
    }
    public void setPcbHasUsedTime(int time) { 
        this.pcbHasUsedTime = time;
    }
    public String getPcbState() { 
        return pcbState; 
    }
    public void setPcbState(String w) { 
        this.pcbState = w; 
    }
    @Override
    public String toString(){
        return  "Pcb{ " +
                "pcbName =" + pcbName + " " +
                ", priority =" + priority +
                ", pcbArrivalTime =" + pcbArrivalTime +
                ", pcnNeedRunningTime =" + pcbNeedRunningTime +
                ", pcbHasUsedTime =" + pcbHasUsedTime +
                ", pcbState =" + pcbState + "}";
    }
}

这里重写了toString()方法,当然是为了更好的输出了!(关于重写与重载的区别,忘了的朋友可以去下面看看)
重载与重写的区别 github

2. 管理进程信息的类写完了,那么接下来干嘛呢?毫无疑问,你需要的是进程执行过程中调用的方法,比如初始化进程啊,排序啊,判断进程是否结束啊等等。有人或许会问,为什么不在Pcb类中写,这个嘛,你不觉得写在一起好挤吗?
那个,需要些什么方法呢?分析分析。。。

初始化进程的方法 这个总要吧,你不能只有一个Pcb类,却不给人家赋值发挥作用吧,那不是占着那啥不那啥嘛。当然你要实在不想动手,那就写个方法给人家自动赋值呗,这多爽,一身轻松!

排序方法 这个也要吧。进程都来了,然后发现不知道谁是老大,谁先执行,那岂不是很尴尬。不行不行,这个得加上。那怎么排呢?别忘了我们实验的流程,每次都执行最高优先级的进程。那要是优先级都相同,怎么办捏?那就按到达时间先后来排嘛,那要是到达时间也相同呢?哪有那么多要是,听我的,我说没有就是没有(小声bb,都一样,亲兄弟还明算账啊,随便啦! )

判断进程结束方法 这个当然也要,不然怎么结束。不要真不行

调度算法 这个给个面子,加上。main()方法里肯定要调用它的,不然前面设计那么多方法干啥。有人可能会说,直接一个一个调用不就行了吗,搞那么多干嘛(其实我是吃了没事干hhh)。其实这就是算法分析过程呈现的内容,你上来就一个全套代码不解释,不太友好!咱尽量一步一步来,授人鱼不如授之以渔。

还有吗? 其实还真有,但那是小事,都是小事了,就没有必要明面上说了。

说了这么多,大佬估计一下就懂了,直接下一篇博客,搞不好嘴里还骂骂咧咧地说道:“这肯定是个sb,写的啥玩意啊。”没事,咱不生气,肯定还有好学者,目不转睛的盯着屏幕,仔细研究,“md,代码在哪呢?”
这么多方法,再搞个类封装一下吧,我就叫它DynamicPriority.java好了。

DynamicPriority.java

import java.util.*;
import java.util.Random;
/**
 * @author GoldenRetriever
 */
public class DynamicPriority {

    /**
     * 进程初始化信息(小蜜蜂输入法)
     * @param pcb  进程
     * @return 返回一个初始化好了的pcb进程
     */
    public static Pcb initByInput(Pcb pcb) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入进程名称:如(进程1)");
        pcb.setPcbName(scanner.nextLine());
        System.out.println("请输入进程优先数:如(5)");
        pcb.setPriority(scanner.nextInt());
        System.out.println("请输入进程到达时间:如(1)");
        pcb.setPcbArrivalTime(scanner.nextInt());
        System.out.println("请输入进程需要运行时间:如(3)");
        pcb.setPcbNeedRunningTime(scanner.nextInt());
        return pcb;
    }

    /**
     * 进程初始化信息(懒者必备,没错就是我)
     * @param pcb 进程
     * @return 返回一个初始化好了的pcb进程
     */
    public static Pcb initByRandom(Pcb pcb) {
        Scanner scanner = new Scanner(System.in);
        Random random = new Random();
        String s = getRandomString(4);
        pcb.setPcbName(s);
        //生成的随机数字在[1,7)之间
        int priorityValue = random.nextInt(6)+1;
        pcb.setPriority(priorityValue);
        int arrivalTimeValue = random.nextInt(6)+1 ;
        pcb.setPcbArrivalTime(arrivalTimeValue);
        int needRunningTimeValue = random.nextInt(6) +1;
        pcb.setPcbNeedRunningTime(needRunningTimeValue);
        return pcb;
    }

    /**
     * 获取随机的字符串方法
     * @param length 字符串长度
     * @return 返回一个字符串
     */
    public static String getRandomString(int length){
        String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random=new Random();
        StringBuffer sb =new StringBuffer();
        for(int i=0;i<length;i++){
            int number=random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }
    /**
     * 先按照优先度排序,优先度相同的按照到达时间去排序
     * @param pcb 进程列表
     */
    public static void sortByPriorityAndArrivalTime(List<Pcb> pcb){
        //使用list中的自定义条件排序方法
        pcb.sort((pcb1, pcb2) -> {
            int cr = 0;
            //先按优先级排升序,数字越小,优先级越高。
            int a = pcb1.getPriority() - pcb2.getPriority();
            if (a != 0) {
                cr = (a < 0) ? -1 : 3;
            } else {
                //再按到达时间排升序
                a = pcb1.getPcbArrivalTime() - pcb2.getPcbArrivalTime();
                if (a != 0) {
                    cr = (a > 0) ? 2 : -2;
                }
            }
            return cr;
        });
        for(Pcb afterPcb: pcb){
            System.out.println("afterSort: "+ afterPcb);
        }

    }
    /**
     * 进程开始运行方法
     * @param pcb 进程
     * @returnp pcb
     */
    public static Pcb hasUsedTimeAdd1(Pcb pcb){
        int time = pcb.getPcbHasUsedTime();
        time++;
        pcb.setPcbHasUsedTime(time);
        System.out.println("进程" + pcb.getPcbName() + "运行一个时间片");
        pcb.setPcbState("Run");
        return pcb;
    }
    /**
     * 判断进程是否完成方法
     * @param pcb 优先级最高的进程
     * @param pcbs  就绪队列中的进程列表
     * @param execpcbs  执行队列中的进程列表
     */
    public static void isTimeToRunningTime(Pcb pcb, List<Pcb> pcbs,  List<Pcb> execpcbs){
        //临时队列,将完成了的进程加入到temp中
        List<Pcb> temp = new ArrayList<>();
        //进程的已用CPU时间等于需要运行时间
        if(pcb.getPcbHasUsedTime() == pcb.getPcbNeedRunningTime()){
            //进程完成,设置进程状态为Finish
            pcb.setPcbState("Finish");
            System.out.println("进程" + pcb.getPcbName() + "已完成");
            //就绪队列删除完成进程,执行队列删除已完成队列
            System.out.println("FinishedPcbInfo:"+pcb.toString());
            System.out.println("***********");
            pcbs.remove(pcb);
            execpcbs.remove(pcb);
        }else{
            //进程优先数加1。
            int n = pcb.getPriority();
            n++;
            pcb.setPriority(n);
            System.out.println("进程"+ pcb.getPcbName() + "" +
                    "优先数+1");
        }
    }
    /**
     * 调度算法函数,最终将需要按顺序执行的进程放入execpcbs中
     * @param pcbs 输入队列
     * @param execpcbs 执行队列
     */
    public static void dispatchpcb(List<Pcb> pcbs, List<Pcb> execpcbs){
        //中间队列,暂存从输入队列中挑选出的进程
        List<Pcb> tempPcb = new ArrayList<>();
        while (!pcbs.isEmpty()){
            //排序
            DynamicPriority.sortByPriorityAndArrivalTime(pcbs);
            System.out.print("就绪队列有: ");
            for(Pcb pcb: pcbs){
                System.out.print(pcb.getPcbName() + " ");
            }
            //判断当前进程是否已完成
            String flag = "Finish";
            //就绪队列首进程添加到运行队列中
            while(!flag.equals(pcbs.get(0).getPcbState())){
                execpcbs.add(pcbs.get(0));
                for(Pcb pcb: execpcbs){
                    System.out.println("执行队列有: " + pcb.getPcbName());
                }
                System.out.println("进程"+pcbs.get(0).getPcbName()+"开始运行");
                //运行时间+1,判断是否到达运行时间
                isTimeToRunningTime(hasUsedTimeAdd1(pcbs.get(0)), pcbs, execpcbs);
                if(pcbs!=null && pcbs.size()>0){
                    execpcbs.remove(pcbs.get(0));
                }
                break;
            }
        }
    }
}

3. Pcb类有了,方法类有了,最后肯定要来一个主类了,总要让程序有入口是吧。主类的工作是啥呢?首先它要提供程序入口main(),然后它要创建进程对象,调用方法类中的方法完成初始化,然后执行调度算法,再然后,好像没有然后了。我主类的工作做完了,剩下的不是他们干吗?

怎么调用就不用我说了吧。

我还是说一下吧。。。

JobRun.java

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * @author GoldenRetriever
 */
public class JobRun {
    public static void main(String[] args) {
        System.out.println("******高优先权调度算法开始:******");
        System.out.println("1.动态优先级算法(输入进程信息)。");
        System.out.println("2.动态优先级算法(随机进程信息)。");
        System.out.println("请输入你想要执行的算法:");
        try (Scanner scanner = new Scanner(System.in)) {
            int x = scanner.nextInt();
            switch (x) {
                case 1:
                    dynamicPriorityInput();
                    break;
                case 2:
                    dynamicPriorityRandomInput();
                    break;
                default:
                    break;
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    /**
     * 进程信息初始化(随机)
     * 我想偷懒
     */
    private static void dynamicPriorityRandomInput() {
        Scanner sc = new Scanner(System.in);
        //输入作业队列
        List<Pcb> pcbs = new ArrayList<>();
        //执行作业队列
        List<Pcb> execpcbs = new ArrayList<>();
        do {
            //创建进程对象
            Pcb pcb = new Pcb();
            //初始化pcb对象然后赋给新对象
            Pcb initPcb = DynamicPriority.initByRandom(pcb);
            //队列添加字符串
            pcbs.add(initPcb);
            System.out.println("已完成一个进程信息初始化,是否继续:(是输入y,否输入n)");
        } while (sc.nextLine().equalsIgnoreCase("y"));
        System.out.println("-----------------");
        //确认初始化成功
        for (Pcb pcb : pcbs) {
            System.out.println(pcb.toString());
        }
        //执行调度算法,将就绪队列按照算法,插入到执行队列中
        DynamicPriority.dispatchpcb(pcbs, execpcbs);
        System.out.println("-----------------");
    }

    /**
     * 进程信息初始化(输入)
     * 不,你不想
     */
    private static void dynamicPriorityInput() {
        System.out.println("请输入进程的相关信息:(输入no代表结束)");
        Scanner sc = new Scanner(System.in);
        //输入作业队列
        List<Pcb> pcbs = new ArrayList<>();
        //执行作业队列
        List<Pcb> execpcbs = new ArrayList<>();
        do {
            //创建进程对象
            Pcb pcb = new Pcb();
            //初始化pcb对象然后赋给新对象
            Pcb initPcb = DynamicPriority.initByInput(pcb);
            //队列添加字符串
            pcbs.add(initPcb);
            System.out.println("是否要继续输入作业相关信息:(是输入yes,否输入no)");
        } while (sc.nextLine().equalsIgnoreCase("yes"));
        System.out.println("-----------------");
        //确认初始化成功
        for (Pcb pcb : pcbs) {
            System.out.println(pcb.toString());
        }
        //执行调度算法,将就绪队列按照算法,插入到执行队列中
        DynamicPriority.dispatchpcb(pcbs, execpcbs);
        System.out.println("-----------------");
    }

}

算法调试

我想偷懒
随机进程信息
随机进程信息
随机进程信息
不,你不想

小蜜蜂输入进程信息
小蜜蜂输入进程信息
小蜜蜂输入进程信息
小蜜蜂输入进程信息

小蜜蜂输入进程信息

结尾感言

第一次在csdn上写文章,可能文章并不是很严谨,然后这个又是针对具体的实验而言,写的不好,或者文章中有任何不足希望指出,虚心接受,坚决不改,开玩笑哈。当然也感谢你能看到最后,这么长也不容易,Thanks。如果有任何能帮到你的地方,那就举个小爪爪,关注下呗,不定期更新哈,不说那么多,拜拜!

  • 11
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值