先来先服务(FCFS)调度算法(Java实现)

简介: 先来先服务(FCFS)调度算法(Java实现)

前言


在操作系统中作业调度的主要任务是根据PCB中的信息,检查系统中的资源能否满足作业对资源的需求,以及按照一定的调度算法从外存的后备队列中选取某些作业调入内存,并为它们创建进程分配必要的资源。本文将以Java程序来实现先来先服务(FCFS)作业调度算法。

一、先来先服务(FCFS)是什么?


FCFS是操作系统中最简单的调度算法,该算法既可用于作业调度,也可以用于进程调度。当在作业调度中采用该算法时,系统将按照作业到达的先后次序来进行调度或者说它是优先考虑在系统中等待时间最长的作业,而不管该作业所需执行时间的长短从后备作业队列中选择几个最先进入该队列的作业,将它们调入内存并为它们分配资源和创建进程。然后把它放入就绪队列

当在进程调度中采用FCFS算法时,每次调度是从就绪的进程队列中选择一个最先进入该队列的进程,为之分配处理机,使之投入运行。该进程一直运行到完成或发生某事件而阻塞后,进程调度程序才将处理机分配给其它进程

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


假设当前有四个进程先后到达系统进行调度:

作业名 到达时间 服务时间
A 0 20
B 5 15
C 10 5
D 15 10

在先来先服务算法中,由于在0时刻系统中只有作业A,因此系统将优先为作业A进行调度。作业A在完成的过程中作业B、C、D分别在5时刻、10时刻、15时刻都到达了系统中。也就是说在作业A调度完成后系统中会有B、C、D三个作业等待调度。根据先来先服务的思想,系统将依次按B、C、D的顺序为接下来的三个作业进行调度。

下面将依次分析各个作业的完成时间、周转时间、带权周转时间与平均带权周转时间

1、作业A:

完成时间:因为作业A从0时刻开始服务,完成时间与服务时间相同为20

周转时间周转时间为从作业提交到作业完成的时间间隔,此时作业A的提交时间为0,完成时间为20,因此作业A的周转时间为20

(20 - 0,也可以说是作业的完成时间 - 到达时间

带权周转时间带权周转时间是指作业的周转时间与系统为它提供服务的时间之比,因为作业A的周转时间为20,系统提供的服务时间为20,因此作业A的带权周转时间为1(20 / 20,作业的周转时间 / 服务时间

2、作业B:

完成时间:因为作业A在20时刻结束服务,所以作业B在20时刻开始服务,完成时间为开始服务时间加服务时间为35(20 + 15)

周转时间:此时作业B的提交时间为5(从5时刻到达系统),完成时间为35,因此作业B的周转时间为30(35 - 5,完成时间 - 到达时

带权周转时间:因为作业B的周转时间为30,系统提供的服务时间为15,因此作业B的带权周转时间为2(30 / 15,周转时间 / 服务时间

3、作业C:

完成时间:因为作业B在35时刻结束服务,所以作业C在35时刻开始服务,完成时间为开始服务时间加服务时间为40(35 + 5)

周转时间:此时作业C的提交时间为10(从10时刻到达系统),完成时间为40,因此作业C的周转时间为30(40 - 10,完成时间 - 到达时间

带权周转时间:因为作业C的周转时间为30,系统提供的服务时间为5,因此作业C的带权周转时间为6(30 / 5,周转时间 / 服务时间

4、作业D:完成时间:因为作业C在40时刻结束服务,所以作业D在40时刻开始服务,完成时间为开始服务时间加服务时间为50(40 + 10)

周转时间:此时作业D的提交时间为15(从15时刻到达系统),完成时间为50,因此作业D的周转时间为35(50 - 15,完成时间 - 到达时间

带权周转时间:因为作业D的周转时间为35,系统提供的服务时间为10,因此作业A的带权周转时间为3.5(35 / 10,周转时间 / 服务时间

作业名 到达时间 服务时间 完成时间 周转时间 带权周转时间
A 0 20 20 20 1
B 5 15 35 30 2
C 10 5 40 30 6
D 15 10 50 35 3.5

平均周转时间:( 20 + 30 + 30 + 35 ) / 4 = 28.75

平均带权周转时间:( 20 / 20 + 30 / 15 + 30 / 5 + 35 / 10 ) / 4 = 3.125

三、实现代码


1、作业数据类


classProcessData {
// 到达时间publicintarriveTime;
// 服务时间publicintserviceTime;
// 完成时间publicintfinishTime;
// 周转时间publicintturnTime;
// 带权周转时间publicdoublepowerTime;
// 作业的构造方法中传来的初值为到达时间和服务时间publicProcessData(intarriveTime, intserviceTime) {
this.arriveTime=arriveTime;
this.serviceTime=serviceTime;
    }
// 重写toString方法便于之后的数据展示@OverridepublicStringtoString() {
returnarriveTime+"\t"+serviceTime+"\t"+finishTime+"\t"+turnTime+"\t"+powerTime;
    }
}

2、作业调度类


publicclassProcessProject {
// 平均周转时间publicstaticdoubleavgTotalTime;
// 平均带权周转时间publicstaticdoubleavgPowerTime;
publicstaticvoidmain(String[] args) {
// 定义长度为4,类型为作业数据类的作业数组用于存储4个作业ProcessData[] processData=newProcessData[4];
// 定义四个作业processData[0] =newProcessData(0, 20);
processData[1] =newProcessData(5, 15);
processData[2] =newProcessData(10, 5);
processData[3] =newProcessData(15, 10);
// 调用先来先服务算法FCFS(processData);
    }
// 先来先服务算法实现privatestaticvoidFCFS(ProcessData[] processData) {
intpreFinished=0; // 前一个作业的完成时间即为下一个作业的开始时间avgTotalTime=0;    // 平均周转时间avgPowerTime=0;  // 平均带权周转时间// 初始化完成时间、周转时间、带权周转时间的初值为0for (inti=0; i<processData.length; i++) {
processData[i].finishTime=0; // 设置初始完成时间为0processData[i].turnTime=0; // 设置初始周转时间为0processData[i].powerTime=0; // 设置初始带权周转时间为0        }
// 如果第一个作业的到达时间不等于前一个作业的完成时间,就将前一个作业的完成时间定义为当前作业的到达时间if (processData[0].arriveTime!=preFinished) {
preFinished=processData[0].arriveTime;
        }
for (inti=0; i<processData.length; i++) {
// 作业的完成时间为上一个作业的完成时间加当前作业的服务时间processData[i].finishTime=preFinished+processData[i].serviceTime;
preFinished=processData[i].finishTime;
// 周转时间 = 完成时间 - 到达时间processData[i].turnTime=processData[i].finishTime-processData[i].arriveTime;
// 带权周转时间 = 作业的周转时间 / 系统提供服务的时间processData[i].powerTime= (double) processData[i].turnTime/ (double) processData[i].serviceTime;
        }
System.out.println("先来先服务(FCFS)算法:");
// 打印进程的信息Display(processData);
    }
privatestaticvoidDisplay(ProcessData[] processData) {
System.out.println("到达时间\t"+"服务时间\t"+"完成时间\t"+"周转时间\t"+"带权周转时间\t");
for (inti=0; i<processData.length; i++) {
System.out.println(processData[i]);
avgTotalTime+=processData[i].turnTime; // 求总周转时间,此时avgTotalTime中存储的值为总周转时间avgPowerTime+=processData[i].powerTime; // 求总带权周转时间,此时avgPowerTime中存储的值为总带权周转时间        }
avgTotalTime=avgTotalTime/processData.length; // 平均周转时间avgPowerTime=avgPowerTime/processData.length; // 平均带权周转时间System.out.println("平均周转时间:"+avgTotalTime);
System.out.println("平均带权周转时间:"+avgPowerTime);
    }
}

3、运行结果


image.png

总结


以上便为操作系统中先来先服务(FCFS)作业调度的Java实现,FCFS算法在单处理机操作系统中已很少作为主调算法,但是经常把它与其它调度算法相结合使用,形成一种更为有效的调度算法。例如,可以在系统中按进程的优先级设置多个队列,每个优先级对应一个队列,其中每一个队列的调度都基于FCFS算法。

相关文章
|
2月前
|
算法 调度 UED
探索操作系统的心脏:调度算法的奥秘与影响
【10月更文挑战第9天】 本文深入探讨了操作系统中至关重要的组件——调度算法,它如同人体的心脏,维持着系统资源的有序流动和任务的高效执行。我们将揭开调度算法的神秘面纱,从基本概念到实际应用,全面剖析其在操作系统中的核心地位,以及如何通过优化调度算法来提升系统性能。
|
2月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
95 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
3天前
|
缓存 算法 搜索推荐
Java中的算法优化与复杂度分析
在Java开发中,理解和优化算法的时间复杂度和空间复杂度是提升程序性能的关键。通过合理选择数据结构、避免重复计算、应用分治法等策略,可以显著提高算法效率。在实际开发中,应该根据具体需求和场景,选择合适的优化方法,从而编写出高效、可靠的代码。
16 6
|
1月前
|
算法 调度
基于遗传模拟退火混合优化算法的车间作业最优调度matlab仿真,输出甘特图
车间作业调度问题(JSSP)通过遗传算法(GA)和模拟退火算法(SA)优化多个作业在并行工作中心上的加工顺序和时间,以最小化总完成时间和机器闲置时间。MATLAB2022a版本运行测试,展示了有效性和可行性。核心程序采用作业列表表示法,结合遗传操作和模拟退火过程,提高算法性能。
|
1月前
|
NoSQL Java 调度
Java调度任务如何保证相同任务在一个周期里只执行一次?
【10月更文挑战第29天】Java调度任务如何保证相同任务在一个周期里只执行一次?
83 6
|
1月前
|
人工智能 算法 大数据
Linux内核中的调度算法演变:从O(1)到CFS的优化之旅###
本文深入探讨了Linux操作系统内核中进程调度算法的发展历程,聚焦于O(1)调度器向完全公平调度器(CFS)的转变。不同于传统摘要对研究背景、方法、结果和结论的概述,本文创新性地采用“技术演进时间线”的形式,简明扼要地勾勒出这一转变背后的关键技术里程碑,旨在为读者提供一个清晰的历史脉络,引领其深入了解Linux调度机制的革新之路。 ###
|
1月前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
71 4
|
1月前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
1月前
|
存储 NoSQL Java
Java调度任务如何使用分布式锁保证相同任务在一个周期里只执行一次?
【10月更文挑战第29天】Java调度任务如何使用分布式锁保证相同任务在一个周期里只执行一次?
100 1
|
1月前
|
算法 大数据 Linux
深入理解操作系统之进程调度算法
【10月更文挑战第24天】本文旨在通过浅显易懂的语言,带领读者深入了解操作系统中的进程调度算法。我们将从进程的基本概念出发,逐步解析进程调度的目的、重要性以及常见的几种调度算法。文章将通过比喻和实例,使复杂的技术内容变得生动有趣,帮助读者建立对操作系统进程调度机制的清晰认识。最后,我们还将探讨这些调度算法在现代操作系统中的应用和发展趋势。