首页 > 编程语言 >Java调度算法实现与应用(FCFS、SJF、RR、HPF)

Java调度算法实现与应用(FCFS、SJF、RR、HPF)

时间:2023-08-07 12:38:36浏览次数:43  
标签:优先级 Java RR servTime FCFS int 任务 new public



文章目录

  • 一、调度算法概述
  • 二、先来先服务(FCFS)算法
  • 1、概述
  • 2、Java实现FCFS
  • 3、优缺点
  • 三、短作业优先 (SJF)算法
  • 1、概述
  • 2、Java实现SJF
  • 3、优缺点
  • 四、时间片轮转(RR)算法
  • 1、概述
  • 2、Java实现RR
  • 3、优缺点
  • 五、优先级调度(HPF)算法
  • 1、概述
  • 2、Java实现HPF


一、调度算法概述

调度算法常见于操作系统中,因为系统资源有限,当有多个进程(或多个进程发出的请求)要使用这些资源时,就必须按照一定的原则选择进程(请求)来占用资源。这就是所谓的调度。在现实生活中也是一样,比如会议室的占用。

应用:
CPU资源调度
云计算资源调度
容器化Docker编排与调度

二、先来先服务(FCFS)算法

1、概述

先来先服务,很好理解,就是按照服务提交申请的顺序,依次执行。讲究先来后到。

2、Java实现FCFS

定义一个Task类作为任务实例,BlockingQueue作为服务队列。

/**
 * 任务类
 */
public class Task {
    //任务名称
    private String name;
    //任务提交的时间
    private Long addTime;
    //任务的执行时间
    private int servTime;
    //任务优先级
    private int level;

    public Task(String name, int servTime) {
        this.name = name;
        this.servTime = servTime;
        this.addTime = System.currentTimeMillis();
    }
    public Task(String name, int servTime,int level) {
        this.name = name;
        this.servTime = servTime;
        this.level = level;
        this.addTime = System.currentTimeMillis();
    }

    public void execute() {
        try {
            // !重点:执行时睡眠,表示该任务耗时servTime毫秒
            Thread.currentThread().sleep(servTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(
                String.format("execute:name=%s,level=%s,addTime=%s,servTime=%s",
                name,level, addTime, servTime));
    }
}
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;

public class FCFS {

    public static void main(String[] args) throws InterruptedException {

        //阻塞队列,FCFS的基础
        final LinkedBlockingQueue<Task> queue = new LinkedBlockingQueue(5);

        //服务线程,任务由该线程获取和执行
        new Thread(new Runnable(){
            @Override
            public void run() {
                while (true) {
                    try {
                        queue.take().execute();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        //向队列中每隔100ms放入一个任务
        for (int i = 0; i < 5; i++) {
            System.out.println("add task:"+i);
            queue.put(new Task("task"+i,new Random().nextInt(1000)));
        }

    }
}

add按顺序放入,时间有序。
execute也按时间顺序执行,而不管后面的servTime,也就是不管执行任务长短,先来先执行。

3、优缺点

多应用于cpu密集型任务场景,对io密集型的不利。

时间相对均衡的业务可以排队处理,比如现实中排队打卡进站。

如果业务需要依赖大量的外部因素,执行时间片长短不一,FCFS算法不利于任务的整体处理进度,可能会因为一个长时间业务的阻塞而造成大量等待。

三、短作业优先 (SJF)算法

1、概述

执行时间短的优先得到资源。即执行前申报一个我需要占据cpu的时间,根据时间长短,短的优先被调度

2、Java实现SJF

使用TreeMap可以实现优先级的任务排序。

import java.util.Map;
import java.util.Random;
import java.util.TreeMap;

public class SJF {
    public static void main(String[] args) throws InterruptedException {
        //有序Map,将服务时间作为key排序
        final TreeMap<Integer,Task> treeMap = new TreeMap();

        //向队列中放入5个任务
        for (int i = 0; i < 5; i++) {
            System.out.println("add task:"+i);
            int servTime = new Random().nextInt(1000);
            //注意,key是servTime,即执行预估时间
            treeMap.put(servTime,new Task("task"+i,servTime));
        }

        //服务线程,任务由该线程获取和执行
        new Thread(new Runnable(){
            @Override
            public void run() {
                while (true) {
                    try {
                        //有序Map中,服务时间短的,置于顶部,那么自然就会优先被取出
                        Map.Entry<Integer,Task> entry = treeMap.pollFirstEntry();
                        if (entry == null){
                            Thread.currentThread().sleep(100);
                        }else {
                            entry.getValue().execute();
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

add任务有序,确实按照从前往后顺序提交的。
execute任务无序,按servtime排序,说明执行时间段的得到了优先执行。

3、优缺点

适用于任务时间差别较大的场景,仍然以进站为例,拿出公交卡的优先刷卡,还没办卡的让一让。

解决了FCFS整体处理时间长的问题,降低平均等待时间,提高了系统吞吐量。

未考虑作业的紧迫程度,因而不能保证紧迫性作业(进程)的及时处理。

对长作业的不利,可能等待很久而得不到执行。

时间基于预估和申报,主观性因素在内,无法做到100%的精准。

四、时间片轮转(RR)算法

1、概述

时间片逐个扫描轮询,轮到谁谁执行。大家公平裁决来者有份,谁也别插队。像是棋牌游戏中的发牌操作,做到了时间和机会上的平均性。

2、Java实现RR

基于数组做为数据插槽方式实现。

public class RR {

    //定义数组作为插槽,每个插槽中可以放入任务
    Integer[] integers;

    //length插槽的个数
    public RR(int length){
        integers = new Integer[length];
    }

    //将任务放入插槽
    public void addTask(int value){
        int slot = 0;
        //不停查找空的插槽
        while (true) {
            //发现空位,将当前任务放入
            if (integers[slot] == null){
                integers[slot] = value;
                System.out.println(String.format("------------------------->add task index=%s,value=%s",slot,value));
                break;
            }
            //如果当前位置有任务占用,看下一个位置
            slot++;
            //如果插槽遍历完还是没有空位置,那么从头开始再找,继续下一个轮回
            if (slot == integers.length){
                slot = 0;
            }
        }
    }
    //执行任务。轮询的策略就在这里
    public void execute(){
        //开启一个线程处理任务。在现实中可能有多个消费者来处理
        new Thread(new Runnable() {
            @Override
            public void run() {
                int index = 0;
                while (true) {
                    //指针轮询,如果到达尾部,下一步重新转向开头
                    // 数据物理结构是一个数组,逻辑上是一个环
                    if (index == integers.length){
                        index = 0;
                    }
                    //如果当前位置没有任务,轮询到下一个插槽
                    if (integers[index] == null){
                        index++;
                        continue;
                    }else{
                        //随机等待,表示模拟当前任务有一个执行时间
                        try {
                            Thread.currentThread().sleep(new Random().nextInt(1000));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //模拟任务执行的内容,也就是打印一下当前插槽和里面的值
                        System.out.println(String.format("execute index=%s,value=%s",index,integers[index]));
                        //执行完,将当前插槽清空,腾出位置来给后续任务使用
                        integers[index] = null;
                    }
                }
            }
        }).start();

    }

    public static void main(String[] args) {
        //测试开始,定义3个插槽
        RR rr = new RR(3);
        //唤起执行者线程,开始轮询
        rr.execute();
        //放置10个任务
        for (int i = 0; i < 10; i++) {
            rr.addTask(i);
        }

    }
}

add任务index无序,value有序,说明是按顺序提交的,但是插槽无序,哪里有空放哪里。
execute执行index有序value无序,说明任务是轮询执行的,每个插槽里的任务不一定是谁。

3、优缺点

做到了机会的相对平均,不会因为某个任务执行时间超长而永远得不到执行。

缺乏任务主次的处理。重要的任务无法得到优先执行,必须等到时间片轮到自己,着急也没用。

五、优先级调度(HPF)算法

1、概述

进程调度每次将处理机分配给具有最高优先级的就绪进程。最高优先级算法可与不同的CPU方式结合形成可抢占式最高优先级算法和不可抢占式最高优先级算法。

2、Java实现HPF

在Task类中新增一个属性level作为优先级标识。
依然使用TreeMap实现排序,注意的是,key要取优先级。

public class HPF {
    public static void main(String[] args) throws InterruptedException {
        //有序Map,将服务优先级作为key排序
        final TreeMap<Integer, Task> treeMap = new TreeMap();


        //向队列中放入5个任务
        for (int i = 0; i < 5; i++) {
            System.out.println("add task:" + i);
            int servTime = new Random().nextInt(1000);
            //注意放入的key,是优先级,这里用i标识
            treeMap.put(i, new Task("task" + i, servTime,i));
        }

        //服务线程,任务由该线程获取和执行
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        //有序Map中,优先级最高的,在底部部,那么自然就会优先被取出
                        Map.Entry<Integer, Task> entry = treeMap.pollLastEntry();
                        if (entry == null) {
                            Thread.currentThread().sleep(100);
                        } else {
                            entry.getValue().execute();
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

按0-4顺序加入task。
执行时,按4-0,优先级高的先得到执行,而与服务时间,加入的时间无关。


标签:优先级,Java,RR,servTime,FCFS,int,任务,new,public
From: https://blog.51cto.com/u_13540373/6992395

相关文章

  • 解决报错:Redis ERR unknown command ‘FLUSHDB‘
    RedisERRunknowncommand‘FLUSHDB’报错信息:ERRunknowncommand`flushdb`ERRunknowncommand`flushall`解决方案:我的redis版本是5.0.7修改配置文件打开/etc/redis/redis.conf文件,将下面两行代码注释掉rename-commandFLUSHALL37_dba_FLUSHALLrename-commandFLUSHDB......
  • k8s 部分节点 nodelocaldns [ERROR] Failed to read node-cache coreFile /etc/coredn
      部分K8S节点nodelocaldnsCrashLoopBackOff状态报错,报错信息如下:#kubectllogsnodelocaldns-w9mgz-nkube-system2023/08/0703:18:33[INFO]UsingCorefile/etc/coredns/Corefile2023/08/0703:18:33[ERROR]Failedtoreadnode-cachecoreFile/etc/coredns/Co......
  • java 异常 java.util.ConcurrentModificationException java 删除集合中满足条件的元
    java异常java.util.ConcurrentModificationExceptionjava.util.ConcurrentModificationException是Java中的一个常见异常,通常在使用迭代器或并发操作时发生。当集合在迭代过程中被修改时,就可能会抛出这个异常。这个异常是为了帮助开发人员发现并发访问集合时的潜在问题。在迭代期......
  • C#.NET 国密SM2 签名验签 与JAVA互通 ver:20230807
    C#.NET国密SM2签名验签与JAVA互通ver:20230807 .NET环境:.NET6控制台程序(.netcore)。JAVA环境:JAVA8(JDK8,JAVA1.8),带maven的JAVA控制台程序。 1.最好要到对方源码(DEMO+JAR包也可以),可以用IDEA反编译(Ctrl+鼠标左键),看它过程逻辑和结果格式。2.常说的SM2签名,指的就......
  • javaee 什么是xml
    一、什么是XML?XML(ExtensibleMarkupLanguage)可扩展标记语言。XML指可扩展标记语言(EXtensibleMarkupLanguage)XML是一种标记语言,很类似HTMLXML的设计宗旨是传输数据,而非显示数据XML标签没有被预定义。您需要自行定义标签。XML被设计为具有自我描述性。XML是W3C的......
  • FileNotFoundError: Could not find module 'xxx.dll'. Try using the full path with
    首先看看报错信息 我的python版本是3.8版本,试了网上加各种办法后发现不行。然后怀疑是系统本身的问题,就下载了visual studio,用其中的dumpbin一查,发现果然少了一个dll文件。详细步骤:1.下载并安装visual studio 2.找到开发者命令工具,并打开 3.在打开的控制台上......
  • javaee 泛型的上下边界和通配符的使用
    下边界packagecom.test.generic;importjava.util.Collection;publicclassTestGenericClass{ //泛型方法?extendsE:泛型的限定 publicstatic<E>voidmove(Collection<E>from,Collection<?superE>to) { for(Ee:from) { to.add(e......
  • Java:Java程序通过执行系统命令调用Python脚本
    本文实现功能:Java程序调用Python脚本Python脚本importsysdefadd(x,y):returnx+yif__name__=="__main__":print(add(int(sys.argv[1]),int(sys.argv[2])))直接执行$pythonmath.py123Java程序调用Python脚本packageio.github.mouday.utils;importja......
  • 了解 Java 内存模型
    Java内存模型(JavaMemoryModel)是Java语言规范定义的一套规则,提供了一组规则和同步机制,以确保多线程程序在多线程环境下正确地处理内存访问的一致性和可见性问题。开发人员在编写多线程程序时,需要遵守Java内存模型的规则,并使用适当的同步机制来保证程序的正确性。1、Java内存模型主......
  • javaee 创建泛型方法
    packagecom.test.generic;importjava.util.Collection;publicclassTestGenericClass{ //泛型方法?extendsE:泛型的限定 publicstatic<E>voidmove(Collection<E>from,Collection<?superE>to) { for(Ee:from) { to.add(e);......