操作系统进程调度 FCFS,SJF,RR算法(Java实现)

有用就给个关注呗

  1. 进程控制块

       为了管理和控制进程,系统在创建每一个进程时,都为其开辟一个专用的存储区,用以随时记录它在系统中的动态特性。通常,把这一存储区称为该进程的“进程控制块”(Process Control Block)。PCB是进程存在的唯一标志

      2.进程容器

        首先是确定三个容器,第一个存放所有进程的信息(只是拿来遍历),第二个为队列进行主要的操作(各种算法下的进出队列操作),第三个用来保存已经处理过后的进程(输出结果,便于观察)。

     3.进程调度算法

        进程调度算法用于确定就绪队列中的哪一个进程即将获得CPU。常用的进程调度算法有先来先服务法、时间片轮转法、优先数法等。

       1) 先来先服务调度算法(FCFS)

         先来先服务调度算法(FCFS):根据进程到达的先后顺序执行进程,不考虑等待时间和执行时间,会产生饥饿现象。属于非抢占式调度,优点是公平,实现简单;缺点是不利于短作业。

    2)短作业(进程)优先调度算法(SJF)

        进程的长短是以进程所要求的运行时间来衡量的。短进程优先(SJF) 调度算法:将处理机分配给绪队列中最短进程,直到完成或发生某事件而阻塞时,进程才释放处理机。

   3)时间片轮转法(RR)

        给每个进程固定的执行时间,根据进程到达的先后顺序让进程在时间片内执行,执行完成后便调度下一个进程执行,自己则返回到就绪队列末尾,排队等待下一次调度的到来。时间片轮转调度不考虑进程等待时间和执行时间,属于抢占式调度。优点是兼顾长短作业;缺点是平均等待时间较长,上下文切换较费时。适用于分时系统。它

        在时间片轮转调度算法中,时间片的大小对系统性能的影响很大。若时间片足够大,以至于所有进程都能在一个时间片内执行完毕,则时间片轮转调度算法就退化为先来先服务调度算法。若时间片很小,,则有利于短作业,因为它能在在该时间片内完成。但是时间片太小,则处理机将在进程间过于频繁地切换,使处理机的开销增大。因此,时间片的大小应选择适当。

代码实现

JCB类

public class JCB {
	String name;//进程名
	double arriveTime;//到达时间
	double serveTime;//服务时间
	double beginTime;//开始时间
	double finshTime;//结束时间
	double roundTime;//周转时间
	double aveRoundTime;//带权周转时间
	double priority;
	double clock=0;//在时间轮转调度算法中,记录该进程真实服务时间已经用时的时长
	boolean firstTimeTag=false;//在RR算法中标识开始时间是否第一次计算
	
	public JCB() {
		
	}
	public JCB(String name, double arriveTime, double serveTime,double priority) {
		//super();
		this.name = name;
		this.arriveTime = arriveTime;
		this.serveTime = serveTime;
		this.priority=priority;
	}
	public String toString() {
		String info=new String("进程名:P"+this.name);
		return info;
	}
}

主类

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
public class processMenu {
	ArrayList<JCB> jcb;// 存放所有进程
	LinkedList<JCB> link;// 存放已经进入队列的进程
	ArrayList<JCB> new_jcb;// 存放按指定调度算法排序后的进程
	JCB nowProess;// 当前应执行进程
 
	public void init() {//初始化
		jcb = new ArrayList<JCB>();
		link = new LinkedList<JCB>();
		new_jcb = new ArrayList<JCB>();
		JCB p1 = new JCB("1", 0, 9,1);
		JCB p2 = new JCB("2", 0.4, 4,2);
		JCB p3 = new JCB("3", 1, 1,3);
		JCB p4 = new JCB("4", 5.5, 4,4);
		JCB p5 = new JCB("5", 7, 2,5);
		jcb.add(p1);jcb.add(p2);jcb.add(p3);jcb.add(p4);jcb.add(p5);
		//先将jcb排序,便于下面的算法实现,就不需要再定义一个标识进程是否已到达的boolean,即无需每次都从头开始扫描jcb容器,
		//而是用一个K记录下当前已经扫描到的位置,一次遍历即可,提高了算法效率。
		Collections.sort(jcb, new compareAt_St());
	}
	public void PCA(){
		ProcessQueue pq=new ProcessQueue();
		pq.EnqueueLast();
		System.out.println("*****************************************************");
		while(!link.isEmpty()) {
			pq.DisplayQueue();//打印当前队列中的进程
			pq.Dequeue();//出队,一次一个
			pq.EnqueueLast();//已到达的进程入队尾
			Collections.sort(link, new compareP());//队列中的进程还需按服务优先级进行排序
		}
	}
 
	public void FCFS(){//先来先服务算法
		ProcessQueue pq=new ProcessQueue();//调用内部类
		pq.EnqueueLast();//让最先到达的进程先入队
		System.out.println("*****************************************************");
		while(!link.isEmpty()) {//while(new_jcb.size()!=jcb.size())
			pq.DisplayQueue();//打印当前队列中的进程
			pq.Dequeue();//出队,一次一个
			pq.EnqueueLast();//已到达的进程入队尾
		}
	}
	public void SJF() {// 短作业优先算法
		ProcessQueue pq=new ProcessQueue();
		pq.EnqueueLast();
		System.out.println("*****************************************************");
		while(!link.isEmpty()) {
			pq.DisplayQueue();//打印当前队列中的进程
			pq.Dequeue();//出队,一次一个
			pq.EnqueueLast();//已到达的进程入队尾
			Collections.sort(link, new compareSt());//队列中的进程还需按服务时间长度进行排序
		}
	}
	public void RR(double sliceTime) {//时间片轮转调度算法
		ProcessQueue pq=new ProcessQueue();
		pq.EnqueueLast();
		System.out.println("*****************************************************");
		while(!link.isEmpty()) {
			pq.DisplayQueue();//打印当前队列中的进程
			pq.Dequeue(sliceTime);//出队,方法参数表示时间片
		}
	}
	
	class ProcessQueue{
		int k = 0;// jcb中的进程遍历时的下标
		double nowTime = 0;// 当前时间
		int i=0;//记录当前出入队列的次数
		public void EnqueueLast() {//进程首次入队,可一次进多个,从队尾进入
			while (k < jcb.size()) {//当遍历完jcb中的所有进程时结束
				if (jcb.get(k).arriveTime <= nowTime) {//已经到达的进程按到达时间先后进入队列
					
					link.addLast(jcb.get(k));
					k++;
				} else {
					break;//如果该进程还未入队,即先结束遍历,保留当前下标k值,注意:此处不要k--;
				}
			}
		}
		public void Dequeue() {//进程出队,一次只出一个
			nowProess = link.removeFirst();//移除队列的队首元素并且返回该对象元素
			nowProess.beginTime = nowTime;//计算开始时间,即为上一个进程的结束时间
			nowProess.finshTime = nowProess.beginTime + nowProess.serveTime;//计算结束时间,该进程开始时间+服务时间
			nowProess.roundTime = nowProess.finshTime - nowProess.arriveTime;//计算周转时间
			nowProess.aveRoundTime = nowProess.roundTime / nowProess.serveTime;//计算带权周转时间
			nowTime = nowProess.finshTime;//获得结束时间,即当前时间,方便判断剩下的进程是否已到达
			new_jcb.add(nowProess);//经处理过数据后加入new_jcb容器
		}
		public void Dequeue(double sliceTime) {//重载Dequeue方法,实现轮转调度算法的出队
			nowProess = link.removeFirst();//移除队列的队首元素并且返回该对象元素
			if(nowProess.firstTimeTag==false) {
				/*轮转调度进程可能会多次反复进出队列,不像FCFS和SJF的进程只会进出一次,所以计算开始时间可以设个标志位,让每个进程在
				 * 第一次执行时记录一遍即可*/
				nowProess.beginTime=nowTime;//进程开始执行的时间
				nowProess.firstTimeTag=true;//计算第一次即可,下次无需更新计算
			}
			if(nowProess.serveTime-nowProess.clock<=sliceTime){//如果当前进程在时间片内运行完,则当前时间累加实际运行时间
				nowTime+=nowProess.serveTime-nowProess.clock;
				nowProess.finshTime=nowTime;//计算该进程完成时间
				nowProess.roundTime = nowProess.finshTime - nowProess.arriveTime;//计算周转时间
				nowProess.aveRoundTime = (double) nowProess.roundTime / nowProess.serveTime;//计算平均周转时间
				new_jcb.add(nowProess);//经处理过数据后加入new_jcb容器
				EnqueueLast();//已到达的进程先入队
			}	
			else{
				nowTime+=sliceTime;//否则,当前时间累加一个时间片
				nowProess.clock+=sliceTime;
				EnqueueLast();//已到达的进程先入队
				link.addLast(nowProess);//上一轮出的再紧接着进入队尾
			}	
		}
		public void DisplayQueue(){//队列中等候的进程
			i++;
			System.out.println("第"+i+"次队列中排队的进程:"+link);
		}
	}
	public void printProcess() {
		double AVGroundTime=0;
		double AVGaveRoundTime=0;
		System.out.println("进程名      到达时间         服务时间       开始时间         完成时间       周转时间    带权周转时间 ");
		for (int i = 0; i < new_jcb.size(); ++i) {
			AVGroundTime=AVGroundTime+new_jcb.get(i).roundTime;
			AVGaveRoundTime=AVGaveRoundTime+new_jcb.get(i).aveRoundTime;
			System.out.println("P"+new_jcb.get(i).name + "    " + new_jcb.get(i).arriveTime + "      " +
		new_jcb.get(i).serveTime+ "     " + new_jcb.get(i).beginTime + "     " + new_jcb.get(i).finshTime +
		"     "+ new_jcb.get(i).roundTime + "    " + new_jcb.get(i).aveRoundTime);
		}
		AVGroundTime=AVGroundTime/5;
		AVGaveRoundTime=AVGaveRoundTime/5;
		System.out.print("平均周转时间:"+AVGroundTime+"   "+"平均带权周转时间"+AVGaveRoundTime+"\n");
		new_jcb.clear();//清空new_jcb容器内的内容,方便存储各种算法的结果并展示
	}
}
 
class compareSt implements Comparator<JCB> {// 按服务时间升序
	public int compare(JCB arg0, JCB arg1) {
		double a=arg0.serveTime - arg1.serveTime;
		if(a>0)
			return 1;
		else
			return -1;
	}
}

class compareP implements Comparator<JCB> {// 按优先级时间升序
	public int compare(JCB arg0, JCB arg1) {
		double a=arg0.priority - arg1.priority;
		if(a>0)
			return 1;
		else
			return -1;
	}
}
class compareAt_St implements Comparator<JCB> {// 按到达时间升序,若到达时间相同,按服务时间升序
	public int compare(JCB o1, JCB o2) {
		double a = o1.arriveTime - o2.arriveTime;
		if (a > 0)
			return 1;
		else if (a == 0) {
			return o1.serveTime > o2.serveTime ? 1 : -1;
		} else
			return -1;
	}
	
	

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		processMenu pm=new processMenu();
		pm.init();//初始化容器
		pm.FCFS();pm.printProcess();
		pm.SJF();pm.printProcess();
		pm.RR(2);pm.printProcess();
		pm.PCA();pm.printProcess();
		
		
	}
}


运行结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值