单道和多道批处理系统+三种常见的作业调度算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ccnuacmhdu/article/details/82825844

单道和多道批处理作业调度算法

批处理就是把一批量的作业放入批处理系统进行处理。主要有两个过程:

  • 把作业调入磁盘(外存)的输入井中(等待被调入内存)
  • 调入内存中被执行

根据批处理系统的道数,分为单道批处理系统和多道批处理系统:

  • 单道批处理系统:一次只允许一个作业调入内存被执行
  • n道批处理系统:一次允许n个作业调入内存被执行

无论单道还是多道,每个时刻都只能执行一个作业。调度算法有很多种,本文只说三种:先来先服务(FCFS)、最短作业优先(SJF)、最高响应比优先(HRRN)。根据批处理的两个步骤,作业调度到内存需要选择其中一个算法,在内存中选择哪个作业执行,还是要选择一个算法。

问题引入

输入作业名称、进入时间、估计运行时间,分别使用单道和多道批处理系统,求出每个作业的开始执行时间、结束时间、周转时间、带权周转时间以及所有作业的平均周转时间和带权平均周转时间。

第二个版本_第二个版本_第二个版本

算法设计

在这里插入图片描述

实验环境及最终源码文件架构

开发工具:记事本
在这里插入图片描述

代码实现

Job.java

import java.util.Comparator;

public class Job{

	private String name;//作业名称
	private String startTime;//作业进入时间
	private String endTime;//作业完成时间
	
	private int executeTime;//作业估计运行时间
	private int executeRemainingTime;//作业估计运行时间的剩余时间
	

	private int startHour;//进入时间对应的小时
	private int startMinute;//进入时间对应的分钟

	private int executeHour;//开始执行时间对应的小时
	private int executeMinute;//开始执行时间对应的分钟
	private String executeStartTime;//开始执行的时间

	private int endHour;//结束时间对应的小时
	private int endMinute;//结束时间对应的分钟
	

	private int turnOverTime;//周转时间,用分钟记
	private double weightedTurnOverTime;//带权周转时间
	
	private boolean state;//标记该作业是否执行完成
	private boolean inMemory;//标记作业是否在内存

	private boolean firstExecute;//标记是否是第一次执行

	public void setName(String name){
		this.name = name;
	}	
	public String getName(){
		return this.name;
	}

	public void setStartTime(String startTime){
		this.startTime = startTime;
	}	
	public String getStartTime(){
		return this.startTime;
	}

	public void setEndTime(String endTime){
		this.endTime = endTime;
	}	
	public String getEndTime(){
		return this.endTime;
	}

	public void setExecuteTime(int executeTime){
		this.executeTime = executeTime;
	}	
	public int getExecuteTime(){
		return this.executeTime;
	}

	public void setExecuteRemainingTime(int executeRemainingTime){
		this.executeRemainingTime = executeRemainingTime;
	}	
	public int getExecuteRemainingTime(){
		return this.executeRemainingTime;
	}

	public void setStartHour(int startHour){
		this.startHour = startHour;
	}
	public int getStartHour(){
		return this.startHour;
	}

	public void setStartMinute(int startMinute){
		this.startMinute = startMinute;
	}
	public int getStartMinute(){
		return this.startMinute;
	}

	public void setEndHour(int endHour){
		this.endHour = endHour;
	}
	public int getEndHour(){
		return this.endHour;
	}

	public void setEndMinute(int endMinute){
		this.endMinute = endMinute;
	}
	public int getEndMinute(){
		return this.endMinute;
	}
	
	public void setTurnOverTime(int turnOverTime){
		this.turnOverTime = turnOverTime;
	}
	public int getTurnOverTime(){
		return this.turnOverTime;
	}

	public void setWeightedTurnOverTime(double weightedTurnOverTime){
		this.weightedTurnOverTime = weightedTurnOverTime;
	}
	public double getWeightedTurnOverTime(){
		return this.weightedTurnOverTime;
	}

	public void setState(boolean state){
		this.state = state;
	}
	public boolean getState(){
		return this.state;
	}

	public void setInMemory(boolean inMemory){
		this.inMemory = inMemory;
	}
	public boolean getInMemory(){
		return this.inMemory;
	}

	public void setExecuteHour(int executeHour){
		this.executeHour = executeHour;
	}
	public int getExecuteHour(){
		return this.executeHour;
	}

	public void setExecuteMinute(int executeMinute){
		this.executeMinute = executeMinute;
	}
	public int getExecuteMinute(){
		return this.executeMinute;
	}

	public void setFirstExecute(boolean firstExecute){
		this.firstExecute = firstExecute;
	}
	public boolean getFirstExecute(){
		return this.firstExecute;
	}

	public void setExecuteStartTime(String executeStartTime){
		this.executeStartTime = executeStartTime;
	}
	public String getExecuteStartTime(){
		return this.executeStartTime;
	}

	
	//测试
	/*
	public static void main(String[] args){
		Job job = new Job();
		job.setName("job");
		job.setStartTime("8:00");
		job.setEndTime("10:00");
		job.setCurrentTime("8:00");
		job.setExecuteTime(50);
		job.setExecuteRemainingTime(50);
		System.out.println(job.getName()+" "+job.getStartTime()+" "+job.getEndTime()+" "+
			job.getCurrentTime()+" "+job.getExecuteTime()+" "+job.getExecuteRemainingTime());
	
		
	}
	*/

}


JobComparator.java

import java.util.Comparator;

//比较器实现Job对象排序,根据时间先后顺序进行
public class JobComparator implements Comparator<Job>{

	public int compare(Job job1, Job job2){
		
		if(job1.getStartHour() < job2.getStartHour()){
			return -1;
		}else if(job1.getStartHour() > job2.getStartHour()){
			return 1;
		}else{
			if(job1.getStartMinute() < job2.getStartMinute()){
				return -1;
			}else if(job1.getStartMinute() > job2.getStartMinute()){
				return 1;
			}else{
				return 0;
			}
		}
	}
}

Bp.java


import java.util.Scanner;
import java.io.File;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.Arrays;
import java.util.Comparator;

public class Bp{

	private int numberOfTracks;//批处理系统道数
	private Job[] jobs;//作业放入的数组
	private int jobCnt;//作业总数
	private int memoryJobCnt;//内存中作业数目
	private int currentHour;//当前时间的小时
	private int currentMinute;//当前时间的分钟
	private String jobAlgorithmOption;//作业调度算法选择标记
	private String processAlgorithmOption;//进程调度算法选择标记

	
	public void setNumberOfTracks(int numberOfTracks){
		this.numberOfTracks = numberOfTracks;
	}
	public int getNumberOfTracks(){
		return this.numberOfTracks;
	}

	public void setJobs(Job[] jobs){
		this.jobs = jobs;
	}
	public Job[] getJobs(){
		return this.jobs;
	}

	public void setJobCnt(int jobCnt){
		this.jobCnt = jobCnt;
	}
	public int getJobCnt(){
		return this.jobCnt;
	}

	public void setMemoryJobCnt(int memoryJobCnt){
		this.memoryJobCnt = memoryJobCnt;
	}
	public int getMemoryJobCnt(){
		return this.memoryJobCnt;
	}

	public void setCurrentHour(int currentHour){
		this.currentHour = currentHour;
	}
	public int getCurrentHour(){
		return this.currentHour;
	}

	public void setCurrentMinute(int currentMinute){
		this.currentMinute = currentMinute;
	}
	public int getCurrentMinute(){
		return this.currentMinute;
	}

	public void setJobAlgorithmOption(String jobAlgorithmOption){
		this.jobAlgorithmOption = jobAlgorithmOption;
	}
	public String getJobAlgorithmOption(){
		return this.jobAlgorithmOption;
	}	

	public void setProcessAlgorithmOption(String processAlgorithmOption){
		this.processAlgorithmOption = processAlgorithmOption ;
	} 
	public String getProcessAlgorithmOption(){
		return processAlgorithmOption;
	} 

	//空参构造
	public void Bp(){}

	//读入数据
	public void input(String path){
		try{
			File in = new File(path);//输入文件
				
			BufferedReader br = new BufferedReader(new FileReader(in));//输入流
				
			int jobCnt = 0;//作业数目
			String line = null;
				
			while((line = br.readLine()) != null){
				
				Job[] jobs = this.getJobs();			

				jobs[jobCnt] = new Job();
					
				//一次读取一行,用空格进行劈开,三个值分别是作业的名称、开始时间、估计运行时间
				String[] splits = line.split(" ");
				jobs[jobCnt].setName(splits[0]);
				jobs[jobCnt].setStartTime(splits[1]);
				jobs[jobCnt].setExecuteTime(Integer.parseInt(splits[2]));
				
				String[] hourMinute = splits[1].split(":");
				jobs[jobCnt].setStartHour(Integer.parseInt(hourMinute[0]));
				jobs[jobCnt].setStartMinute(Integer.parseInt(hourMinute[1]));
				
				jobs[jobCnt].setExecuteRemainingTime(Integer.parseInt(splits[2]));
					
				jobs[jobCnt].setState(false);
				jobs[jobCnt].setInMemory(false);

				jobs[jobCnt].setFirstExecute(true);

				jobCnt++;//每读进来一个作业,作业数目加1

			}
			br.close();//关闭流,否则可能I/O操作失败
			this.setJobCnt(jobCnt);
			this.setCurrentHour(jobs[0].getStartHour());
			this.setCurrentMinute(jobs[0].getStartMinute());

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

	}
	
	public void jobFCFS(){
		Job[] jobs = this.getJobs();
		int times = this.getNumberOfTracks() - this.getMemoryJobCnt();
		int tmpCnt = 0;//临时变量,累计本次调入内存的数目,最多达到times个
		int jobCnt = this.getJobCnt();
		int currentHour = this.getCurrentHour();	
		int currentMinute = this.getCurrentMinute();		
		int memoryJobCnt = this.getMemoryJobCnt();		

		for(int i =0 ;i < jobCnt; i++){
			if(tmpCnt >= times){break;}//如果调入内存的作业数目大于了本次内存允许调用的数目,终止。若只允许调入1个,那么tmpCnt=1时候终止循环
			if((jobs[i].getStartHour() < currentHour || (jobs[i].getStartHour() == currentHour && jobs[i].getStartMinute() <= currentMinute)) 
					&& jobs[i].getInMemory()==false && jobs[i].getState() == false){
				jobs[i].setInMemory(true);
				memoryJobCnt++;
				tmpCnt++;
			}
		}
		this.setMemoryJobCnt(memoryJobCnt);

	}

	public void jobSJF(){
		Job[] jobs = this.getJobs();
		int times = this.getNumberOfTracks() - this.getMemoryJobCnt();
		int jobCnt = this.getJobCnt();
		int currentHour = this.getCurrentHour();	
		int currentMinute = this.getCurrentMinute();		
		int memoryJobCnt = this.getMemoryJobCnt();		

		//暴力挑选最多times个最短作业到内存
		while(times>0){
			int minimumTime = 1000000;//假定最长时间不超过1000000
			int pos = -1;//本次要选谁去内存
			for(int i =0 ;i < jobCnt; i++){
				
				if((jobs[i].getStartHour() < currentHour || (jobs[i].getStartHour() == currentHour && jobs[i].getStartMinute() <= currentMinute)) 
					&& jobs[i].getInMemory()==false && jobs[i].getState() == false && jobs[i].getExecuteTime() < minimumTime){
					minimumTime = jobs[i].getExecuteTime();
					pos = i;
					
				}
			}
			if(pos != -1){
				jobs[pos].setInMemory(true);
				memoryJobCnt++;
			}
			times--;
		}
		
		this.setMemoryJobCnt(memoryJobCnt);

	}

	public void jobHRRN(){

		Job[] jobs = this.getJobs();
		int times = this.getNumberOfTracks() - this.getMemoryJobCnt();
		int jobCnt = this.getJobCnt();
		int currentHour = this.getCurrentHour();	
		int currentMinute = this.getCurrentMinute();		
		int memoryJobCnt = this.getMemoryJobCnt();		

		//暴力挑选最多times个最高响应比作业到内存
		while(times>0){
			double responseRatio = -1.0;//最高响应比
			int pos = -1;//本次要选谁去内存
			for(int i =0 ;i < jobCnt; i++){
				int waitTime = (currentHour - jobs[i].getStartHour() - 1)*60 + 60 +currentMinute - jobs[i].getStartMinute();
				double tmpRatio = (double)waitTime/(double)jobs[i].getExecuteTime();
				if((jobs[i].getStartHour() < currentHour || (jobs[i].getStartHour() == currentHour && jobs[i].getStartMinute() <= currentMinute)) 
					&& jobs[i].getInMemory()==false && jobs[i].getState() == false && tmpRatio > responseRatio ){
					responseRatio = tmpRatio;
					pos = i;
					
				}
			}
			if(pos != -1){
				jobs[pos].setInMemory(true);
				memoryJobCnt++;
			}
			times--;
		}
		
		this.setMemoryJobCnt(memoryJobCnt);
	}


	public int processFCFS(){

		Job[] jobs = this.getJobs();	
		int jobCnt = this.getJobCnt();

		//************************从内存选一个作业(准备执行)************************
		//作业已经调入内存,并且此刻内存中必定有没有执行完的作业。因为系统是串行的,必定选择一个作业执行。
		//选择以当前时间为起点最先来的作业执行
		int pos = -1;
		for(int i = 0; i < jobCnt ;i++){
			if(jobs[i].getInMemory()==true){
				pos = i;
				break;
			}
		}
		return pos;
	}

	public int processSJF(){
		
		Job[] jobs = this.getJobs();	
		int jobCnt = this.getJobCnt();

		//************************从内存选一个作业(准备执行)************************
		//作业已经调入内存,并且此刻内存中必定有没有执行完的作业。因为系统是串行的,必定选择一个作业执行。
		//选择以当前时间为起点运行时间最短的作业执行
			
		int minimumTime = 1000000;//假定最长作业时间不会超过1000000
		int pos = -1;//最短作业对应的数组下标
		for(int i = 0; i < jobCnt ;i++){
			if(jobs[i].getInMemory()==true && jobs[i].getExecuteRemainingTime() < minimumTime){
				minimumTime = jobs[i].getExecuteRemainingTime();
				pos = i;
			}
		}
		return pos;
	}

	public int processHRRN(){

		Job[] jobs = this.getJobs();	
		int jobCnt = this.getJobCnt();
		int currentHour = this.getCurrentHour();
		int currentMinute = this.getCurrentMinute();

		//************************从内存选一个作业(准备执行)************************
		//作业已经调入内存,并且此刻内存中必定有没有执行完的作业。因为系统是串行的,必定选择一个作业执行。
		//选择以当前时间为起点最高响应比的作业执行
			
		double responseRatio = -1.0;
		int pos = -1;//最短作业对应的数组下标
		for(int i = 0; i < jobCnt ;i++){
			int waitTime = (currentHour - jobs[i].getStartHour() - 1)*60 + 60 +currentMinute - jobs[i].getStartMinute();
			double tmpRatio = (double)waitTime/(double)jobs[i].getExecuteTime();
			if(jobs[i].getInMemory()==true && tmpRatio>responseRatio){
				responseRatio = tmpRatio;
				pos = i;
			}
		}
		return pos;
	}
	
	public void exe(int pos){

		Job[] jobs = this.getJobs();
		int memoryJobCnt = this.getMemoryJobCnt();
		int jobCnt = this.getJobCnt();
		int numberOfTracks = this.getNumberOfTracks();
		int currentHour = this.getCurrentHour();
		int currentMinute = this.getCurrentMinute();
		
		//************************执行选择的那个作业(开始执行)************************
		//(1)如果当前内存已经满了的话,直接执行完成jobs[pos]即可。
		//(2)如果当前内存未满并且所有未完成的作业都已经调入到了内存,仍然是直接执行完成jobs[pos]即可。
		//(3)如果不是上面两种情况,即内存未满,且存在作业没有调入到内存。这种情况下,要考虑该作业执行过程中,
		//     是否需要调入新作业到内存。由于上面已经完成了作业调入内存的功能,那么这次调入内存的作业也只会有
		//     一个!这一个一定选择此刻尚未完成、未在内存、开始时间最靠前的作业。还需要判断本次作业执行过程中
		//     的时间和将要调入作业的开始时间的关系。
		//     A:本次作业执行完时,将要调入的作业尚未开始。那就需要执行完本次作业。并且把当前时间修改为将要调
		//       入的这个作业的开始时间。
		//     B:本次作业执行过程中,将要调入的作业来了,那就需要把当前时间设置为将要调入的作业的开始时间,并
		//       且设置本次作业的剩余执行时间。
		//     C:本次作业开始执行的时候,将要调入的作业早已经来过了。这种情况直接交给上面的调入内存步骤解决之。
			
		//针对(1)(2)两种情形
		if(memoryJobCnt == numberOfTracks || memoryJobCnt == jobCnt - this.getFinishedNumber(jobs, jobCnt)){

			//先设置下开始执行的时间
			if(jobs[pos].getFirstExecute() == true){
				jobs[pos].setFirstExecute(false);
				jobs[pos].setExecuteHour(currentHour);
				jobs[pos].setExecuteMinute(currentMinute);
				jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
			}

			jobs[pos].setState(true);
			jobs[pos].setEndHour(currentHour + (jobs[pos].getExecuteRemainingTime() + currentMinute)/60);
			jobs[pos].setEndMinute((jobs[pos].getExecuteRemainingTime() + currentMinute) % 60);
			jobs[pos].setInMemory(false);
			memoryJobCnt--;
			this.setMemoryJobCnt(memoryJobCnt);
		
			//该作业执行完,要设置当前时间
			currentHour = jobs[pos].getEndHour();
			currentMinute = jobs[pos].getEndMinute();

			//再次设置当前时间
			//如果当前内存中的所有作业都执行完之后,还存在内存外尚未执行的作业X,且X的开始时间在当前时间之后,则需要
			//把这样的作业调入内存,那么要把当前时间设置为X的开始时间,为X调入内存做准备。注意这个X就是目前在外存中,
			//且没有完成、且开始时间在目前时间之后,且在所有外存尚未开始执行的作业中开始时间最早。
			if(memoryJobCnt==0 && this.getFinishedNumber(jobs, jobCnt)<jobCnt){
				for(int i = 0; i < jobCnt; i++){
					if(jobs[i].getInMemory()==false && jobs[i].getState()==false){
							
						if(jobs[i].getStartHour()>currentHour || (jobs[i].getStartHour()==currentHour && jobs[i].getStartMinute()>currentMinute)){
								
							currentHour = jobs[i].getStartHour();						
							currentMinute = jobs[i].getStartMinute();
						}
						break;
					}
				}
			}	
			this.setCurrentHour(currentHour);
			this.setCurrentMinute(currentMinute);		
		}else {
			//选中没有完成且不在内存的最先来的作业
			int tmpPos = -1;
			for(int i = 0; i < jobCnt; i++){
				if(jobs[i].getState()==false && jobs[i].getInMemory()==false){
					tmpPos = i;
					break;
				}
			}
				
				
			//A:本次作业执行完时,将要调入的作业尚未开始
			if(
				(  (jobs[pos].getExecuteRemainingTime()+ currentMinute)/60 + currentHour < jobs[tmpPos].getStartHour() 
					  || (
					(jobs[pos].getExecuteRemainingTime()+currentMinute)/60 + currentHour == jobs[pos+1].getStartHour() 
					&& 
					(jobs[pos].getExecuteRemainingTime()+currentMinute)%60 <= jobs[pos+1].getStartMinute()
					)
				)
				){
					
				//先设置下开始执行的时间
				if(jobs[pos].getFirstExecute() == true){
					jobs[pos].setFirstExecute(false);
					jobs[pos].setExecuteHour(currentHour);
					jobs[pos].setExecuteMinute(currentMinute);
					jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
				}

				jobs[pos].setState(true);
				jobs[pos].setEndHour(currentHour + (jobs[pos].getExecuteRemainingTime() + currentMinute)/60);
				jobs[pos].setEndMinute((jobs[pos].getExecuteRemainingTime() + currentMinute) % 60);
				jobs[pos].setInMemory(false);
				memoryJobCnt--;
				this.setMemoryJobCnt(memoryJobCnt);
				//该作业执行完,要设置当前时间
				currentHour = jobs[tmpPos].getStartHour();
				currentMinute = jobs[tmpPos].getStartMinute();

				this.setCurrentHour(currentHour);
				this.setCurrentMinute(currentMinute);
			}else if(
					(  (jobs[pos].getExecuteRemainingTime()+ currentMinute)/60 + currentHour > jobs[tmpPos].getStartHour() 
					      || (
						 (jobs[pos].getExecuteRemainingTime()+currentMinute)/60 + currentHour == jobs[pos+1].getStartHour() 
						 && 
					  (jobs[pos].getExecuteRemainingTime()+currentMinute)%60 > jobs[pos+1].getStartMinute()
					)
					)
				){
						
				// B:本次作业执行过程中,将要调入的作业来了
					
				//先设置下开始执行的时间
				if(jobs[pos].getFirstExecute() == true){
					jobs[pos].setFirstExecute(false);
					jobs[pos].setExecuteHour(currentHour);
					jobs[pos].setExecuteMinute(currentMinute);
					jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
				}
		
				int tmpTime = (jobs[tmpPos].getStartHour() - 1 - currentHour)*60 + 60 + jobs[tmpPos].getStartMinute() - currentMinute;
				jobs[pos].setExecuteRemainingTime(jobs[pos].getExecuteRemainingTime()-tmpTime);
				currentHour = jobs[tmpPos].getStartHour();
				currentMinute = jobs[tmpPos].getStartMinute();
				this.setCurrentHour(currentHour);
				this.setCurrentMinute(currentMinute);
			}
				
		}	

	}

	
	public void output(){

		Job[] jobs = this.getJobs();
		int jobCnt = this.getJobCnt();
		
		
		System.out.println("====================================================================================================================");
		
		//计算周转时间、带权周转时间、平均周转时间和平均带权周转时间
		//输出
		System.out.println("作业\t进入时间\t估计运行时间(分钟)\t开始时间\t结束时间\t周转时间(分钟)\t带权周转时间");
		
		double averageTurnOverTime = 0.0;
		double weightedAverageTurnOverTime = 0.0;
		for(int i = 0; i < jobCnt; i++){
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			//计算周转时间
			int tmpTime = (jobs[i].getEndHour() - jobs[i].getStartHour() -1)*60 + 60 + jobs[i].getEndMinute() - jobs[i].getStartMinute();;
			
			jobs[i].setTurnOverTime(tmpTime);
			jobs[i].setWeightedTurnOverTime((jobs[i].getTurnOverTime()+0.0)/(0.0+jobs[i].getExecuteTime()));
			
			averageTurnOverTime += (double)jobs[i].getTurnOverTime();
			weightedAverageTurnOverTime += (double)jobs[i].getWeightedTurnOverTime();
			System.out.println(jobs[i].getName()+"\t"+jobs[i].getStartTime()+"\t\t\t"+jobs[i].getExecuteTime()+"\t\t"+jobs[i].getExecuteStartTime()+"\t\t"+jobs[i].getEndTime()+"\t\t"+
				jobs[i].getTurnOverTime()+"\t\t\t"+jobs[i].getWeightedTurnOverTime());
		
		}
		
		//输出平均周转时间和平均带权周转时间
		System.out.println();
		System.out.println("平均周转时间: "+(averageTurnOverTime/jobCnt)+"分钟");
		System.out.println("平均带权周转时间:"+(weightedAverageTurnOverTime/jobCnt));
		System.out.println("====================================================================================================================");
	

	}


	//计算已经完成的作业数目
	public int getFinishedNumber(Job[] jobs, int jobCnt){

		int num = 0;
		for(int i = 0; i < jobCnt; i++){
			if(jobs[i].getState() == true){
				num ++;
			}
		}
		return num;
	}
}

Run.java

/*

	//作者:ccnuacmhdu(CSDN博主)
	//时间:2018/9/28
	
	************************************本代码:分别在单道和多道批处理系统下实现三种常见的作业调度算法(FCFS,SJF,HRRN)************************************
	
	【编程语言及工具】Java+记事本+JDK8
	
	【约定】在一天之内完成,在程序执行过程中,小时只能在0-24,分钟只能在0-59

	【输入】与源代码同文件夹下的in.txt

*/


import java.util.Scanner;
import java.util.Arrays;
import java.util.Comparator;

public class Run{

	public static void main(String[] args){
		
		Scanner scan = new Scanner(System.in);	

		while(true){

			Bp bp = new Bp();
		
			Job[] jobs = new Job[100];//假定总作业数目不超过100
			bp.setJobs(jobs);
		
			//数据输入的文件
			String path = "in.txt";
			//输入数据
			bp.input(path);
			//给作业按照时间先后进行排序
			Comparator<Job> jobComparator = new JobComparator();//用泛型,否则报错:-Xlint:unchecked重新编译
			Arrays.sort(jobs, 0, bp.getJobCnt(), jobComparator);
			
			System.out.println("welcome-----welcome-----welcome-----welcome");
			System.out.print("请输入批处理系统道数: ");
			int numberOfTracks = scan.nextInt();
			bp.setNumberOfTracks(numberOfTracks);				

			String jobAlgorithmOption = null;//作业调度算法选择标记
			String processAlgorithmOption = null;//进程调度算法选择标记
			//作业调度算法选择菜单,由用户选择输入
			System.out.println();
			System.out.println("**********************Option**********************");
			System.out.println("1>>>>>>>>>>FCFS(first-come-first-service");
			System.out.println("2>>>>>>>>>>SJF(shortest job first)");
			System.out.println("3>>>>>>>>>>HRRN(Highest Response Ratio Next)");
						
			System.out.print("请选择作业调度算法编号: ");
			jobAlgorithmOption = scan.next();
			bp.setJobAlgorithmOption(jobAlgorithmOption);
		
			System.out.print("请选择进程调度算法编号: ");
			processAlgorithmOption = scan.next();
			bp.setProcessAlgorithmOption(processAlgorithmOption);
			
			while(bp.getFinishedNumber(bp.getJobs(), bp.getJobCnt()) < bp.getJobCnt()){
				//**************************第一步:调度作业到内存**********************************
				switch(bp.getJobAlgorithmOption()){
					
					case "1":bp.jobFCFS();
						 break;
					case "2":bp.jobSJF();
						 break;
					case "3":bp.jobHRRN();
						 break;
					default:System.out.println("input error");
						return;
				}
				
				//**************************第二步:从内存中选一个作业执行**************************
				int pos;
				switch(bp.getProcessAlgorithmOption()){
					
					case "1":pos = bp.processFCFS();
						 break;
					case "2":pos = bp.processSJF();
						 break;
					case "3":pos = bp.processHRRN();
						 break;
					default:System.out.println("input error");
						return;
				}
				
				//执行这个作业
				bp.exe(pos);
			}
			
			//输出
			bp.output();

		}
	}
	
}

实验结果

输入方式:in.txt
运行环境:JDK8
命令行运行:切换到源代码目录下,输入命令
javac Run.java
java Run

单道批处理系统测试

in.txt数据:
job1 8:00 120
job2 8:50 50
job3 9:00 10
job4 9:50 20

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

多道批处理系统测试

更换in.txt数据为:
job1 10:00 30
job2 10:05 20
job3 10:10 5
job4 10:20 10
在这里插入图片描述

第一个版本_第一个版本_第一个版本

算法设计

该版本,多道批处理系统下,作业调度采用的是先来先服务,进程调度则是选择三个算法之一。单道批处理系统下,作业调度采用的是三种算法之一。由于单道批道处理系统下,只有一个作业调度进入内存,那么进程调度选择哪一个都无所谓,结果都一样,因为只能执行调入内存中的这一个作业,别无选择。
在这里插入图片描述

实现分析及编程环境

开发工具:记事本
编程语言:Java
由上面的算法设计,思路非常清晰,笔者设计了两个类:作业类(Job.java)和批处理类(Bp.java)。具体代码及细节处理详细见代码。

代码实现


/*
	
	************************************本代码:分别在单道和多道批处理系统下实现三种常见的作业调度算法(FCFS,SJF,HRRN)************************************
	
	【约定】在一天之内完成,在程序执行过程中,小时只能在0-24,分钟只能在0-59
	
	【先明确一点】笔者为了让每个算法对应的函数能完整地执行好一种作业调度策略,每个函数包含了读写等完整操作。
		      ******代码量较大,用代码量换取每个函数功能的完整性。这是笔者本次采取的书写代码风格******
		      ******只要清楚其中一个调度算法的函数代码,其他调度策略对应的函数只需更改关键的几行代码即可实现

	【多道批处理系统调度思路】:根据当前时刻,调入适当数量的作业到内存;根据调度算法选择当前内存中最优的作业执行。
		
	
	【单道与多道调度区别写不同函数的理由】多道批处理系统采取的策略:先来的先调入内存,再判断先执行谁。
		              		      单道批处理系统采取的策略:对于当前时间点及之前已经到来的所有作业中,直接判断先执行谁,然后就开始执行之。
					      单道下,先来先服务就是多道下的先来先服务

	【输入】文件,与源文件同文件夹下的in.txt

	【函数对应算法】见名知意
		public void FCFS(int numberOfTracks){}
		public void SJF(int numberOfTracks){}
		public void HRRN(int numberOfTracks){}
		单道下,先来先服务就是多道下的先来先服务
		public void singleSJF(){}
		public void singleHRRN(){}
	


*/


import java.util.Scanner;
import java.io.File;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.Arrays;
import java.util.Comparator;

public class Bp{
	
	//程序入口,主函数
	public static void main(String[] args){
	
		int numberOfTracks = 2;//批处理系统的道数,由用户输入,默认2道
		String option = null;//作业调度算法种类标志,由用户输入
	
		Scanner scan = new Scanner(System.in);
		
		Bp bp = new Bp();
		
		while(true){

			//作业调度算法选择菜单,由用户选择输入
			System.out.println();
			System.out.println("**********************Option**********************");
			System.out.println("1(多道)>>>>>>>>>>FCFS(first-come-first-service");
			System.out.println("2(多道)>>>>>>>>>>SJF(shortest job first)");
			System.out.println("3(多道)>>>>>>>>>>HRRN(Highest Response Ratio Next)");
			System.out.println("a(单道)>>>>>>>>>>FCFS(first-come-first-service");
			System.out.println("b(单道)>>>>>>>>>>SJF(shortest job first)");
			System.out.println("c(单道)>>>>>>>>>>HRRN(Highest Response Ratio Next)");
			System.out.println("0>>>>>>>>>>exit");
			System.out.print("请选择算法编号: ");
			option = scan.next();
			if(option.equals("1") || option.equals("2") || option.equals("3")){
				System.out.print("由于您选择多道批处理,请输入道数: ");
				numberOfTracks = scan.nextInt();
			}
			switch(option){
				case "0": 
					return;
				case "1": 
					bp.FCFS(numberOfTracks);
					break;
				case "2":
					bp.SJF(numberOfTracks);
					break;
				case "3":
					bp.HRRN(numberOfTracks);
					break;
				case "a":
					bp.FCFS(1);
					break;
				case "b":
					bp.singleSJF();
					break;
				case "c":
					bp.singleHRRN();
					break;
				
				default:
					System.out.println("输入错误,请根据菜单提示输入算法编号!");
				
			}
		}
		
	}
	
	public void FCFS(int numberOfTracks){
		
		System.out.println("====================================================================================================================");
		System.out.println("The algorithm is FCFS. And the input and output are as follows.");
		System.out.println();
		//存放待调度的作业对象,假设不超过100个作业
		Job[] jobs = new Job[100];//注意这数组中都是引用变量,每个引用变量默认值是null
		int jobCnt = 0;//作业总数记录
		
		
		
		try{
			File in = new File("in.txt");//输入文件
			//File out = new File("out.txt");//输出文件
			BufferedReader br = new BufferedReader(new FileReader(in));//输入流
			//BufferedWriter bw = new BufferedWriter(new FileWriter(out));//输出流

			String line = null;
			//从文件in.txt读入数据
			while((line = br.readLine()) != null){
				
				jobs[jobCnt] = new Job();
				
				//一次读取一行,用空格进行劈开,三个值分别是作业的名称、开始时间、估计运行时间
				String[] splits = line.split(" ");
				jobs[jobCnt].setName(splits[0]);
				jobs[jobCnt].setStartTime(splits[1]);
				jobs[jobCnt].setExecuteTime(Integer.parseInt(splits[2]));
				
				String[] hourMinute = splits[1].split(":");
				jobs[jobCnt].setStartHour(Integer.parseInt(hourMinute[0]));
				jobs[jobCnt].setStartMinute(Integer.parseInt(hourMinute[1]));
				
				jobs[jobCnt].setExecuteRemainingTime(Integer.parseInt(splits[2]));
				
				jobs[jobCnt].setState(false);
				jobs[jobCnt].setInMemory(false);

				jobs[jobCnt].setFirstExecute(true);
			
				//写入文件out.txt
				//bw.write(line,0,line.length());
				//bw.newLine();

				jobCnt++;//每读进来一个作业,作业数目加1
			}

			br.close();//关闭流,否则可能I/O操作失败
			//bw.close();//关闭流,否则可能I/O操作失败
		}catch(Exception e){
			e.printStackTrace();
		}

		Comparator<Job> jobComparator = new JobComparator();//用泛型,否则报-》请使用 -Xlint:unchecked 重新编译
		Arrays.sort(jobs, 0, jobCnt, jobComparator);//按照时间先后给作业排序
		
		

		//到此,数据已经加载完毕,并根据时间的先后顺序进行了排序,下面进入核心算法
		//第一步,每个时间点,调度谁去内存
		//第二步,每个时间点,执行哪个作业

		//当前没有完成的作业分两类,一类是在内存中,一类是不在内存中
		int memoryJobCnt = 0;//内存中作业数目
		int notMemoryJobCnt = jobCnt - getFinishedNumber(jobs, jobCnt) - memoryJobCnt;//当前没有完成且不在内存的作业数目
		
		
		//当前时间
		int currentHour = jobs[0].getStartHour();
		int currentMinute = jobs[0].getStartMinute();
		
		//存在作业没执行的话,就一直执行
		while(getFinishedNumber(jobs, jobCnt) < jobCnt){
			//************************调作业到内存************************
			//选几个还没有完成的、不在内存的作业调入内存。需要明确一点:先来的先调入!
			//最多选(numberOfTracks-memoryJobCnt)=times个已经到来的作业调入内存

			int times = numberOfTracks - memoryJobCnt;
			int tmpCnt = 0;//临时变量,累计本次调入内存的数目,最多达到times个
			
			for(int i =0 ;i < jobCnt; i++){
				if(tmpCnt >= times){break;}//如果调入内存的作业数目大于了本次内存允许调用的数目,终止。若只允许调入1个,那么tmpCnt=1时候终止循环
				if((jobs[i].getStartHour() < currentHour || (jobs[i].getStartHour() == currentHour && jobs[i].getStartMinute() <= currentMinute)) 
						&& jobs[i].getInMemory()==false && jobs[i].getState() == false){
					jobs[i].setInMemory(true);
					notMemoryJobCnt--;
					memoryJobCnt++;
					tmpCnt++;
				}
			}

			//************************【【【【算法核心】】】从内存选一个作业(准备执行)************************
			//作业已经调入内存,并且此刻内存中必定有没有执行完的作业。因为系统是串行的,必定选择一个作业执行。
			//选择最先来的
			int pos = -1;
			for(int i = 0; i < jobCnt ;i++){
				if(jobs[i].getInMemory()==true){
					pos = i;
					break;
				}
			}
			
			//************************执行选择的那个作业(开始执行)************************
			//(1)如果当前内存已经满了的话,直接执行完成jobs[pos]即可。
			//(2)如果当前内存未满并且所有未完成的作业都已经调入到了内存,仍然是直接执行完成jobs[pos]即可。
			//(3)如果不是上面两种情况,即内存未满,且存在作业没有调入到内存。这种情况下,要考虑该作业执行过程中,
			//     是否需要调入新作业到内存。由于上面已经完成了作业调入内存的功能,那么这次调入内存的作业也只会有
			//     一个!这一个一定选择此刻尚未完成、未在内存、开始时间最靠前的作业。还需要判断本次作业执行过程中
			//     的时间和将要调入作业的开始时间的关系。
			//     A:本次作业执行完时,将要调入的作业尚未开始。那就需要执行完本次作业。并且把当前时间修改为将要调
			//       入的这个作业的开始时间。
			//     B:本次作业执行过程中,将要调入的作业来了,那就需要把当前时间设置为将要调入的作业的开始时间,并
			//       且设置本次作业的剩余执行时间。
			//     C:本次作业开始执行的时候,将要调入的作业早已经来过了。这种情况直接交给上面的调入内存步骤解决之。
			
			//针对(1)(2)两种情形
			if(memoryJobCnt == numberOfTracks || memoryJobCnt == jobCnt - getFinishedNumber(jobs, jobCnt)){

				//先设置下开始执行的时间
				if(jobs[pos].getFirstExecute() == true){
					jobs[pos].setFirstExecute(false);
					jobs[pos].setExecuteHour(currentHour);
					jobs[pos].setExecuteMinute(currentMinute);
					jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
				}

				jobs[pos].setState(true);
				jobs[pos].setEndHour(currentHour + (jobs[pos].getExecuteRemainingTime() + currentMinute)/60);
				jobs[pos].setEndMinute((jobs[pos].getExecuteRemainingTime() + currentMinute) % 60);
				jobs[pos].setInMemory(false);
				memoryJobCnt--;
		
				//该作业执行完,要设置当前时间
				currentHour = jobs[pos].getEndHour();
				currentMinute = jobs[pos].getEndMinute();

				//再次设置当前时间
				//如果当前内存中的所有作业都执行完之后,还存在内存外尚未执行的作业X,且X的开始时间在当前时间之后,则需要
				//把这样的作业调入内存,那么要把当前时间设置为X的开始时间,为X调入内存做准备。注意这个X就是目前在外存中,
				//且没有完成、且开始时间在目前时间之后,且在所有外存尚未开始执行的作业中开始时间最早。
				if(memoryJobCnt==0 && getFinishedNumber(jobs, jobCnt)<jobCnt){
					for(int i = 0; i < jobCnt; i++){
						if(jobs[i].getInMemory()==false && jobs[i].getState()==false){
							
							if(jobs[i].getStartHour()>currentHour || (jobs[i].getStartHour()==currentHour && jobs[i].getStartMinute()>currentMinute)){
								
								currentHour = jobs[i].getStartHour();						
								currentMinute = jobs[i].getStartMinute();
							}
							break;
						}
					}
				}
				
				
			}else {
				//选中没有完成且不在内存的最先来的作业
				int tmpPos = -1;
				for(int i = 0; i < jobCnt; i++){
					if(jobs[i].getState()==false && jobs[i].getInMemory()==false){
						tmpPos = i;
						
						break;
					}
				}
				
				
				//A:本次作业执行完时,将要调入的作业尚未开始
				if(
					(  (jobs[pos].getExecuteRemainingTime()+ currentMinute)/60 + currentHour < jobs[tmpPos].getStartHour() 
					   || (
						(jobs[pos].getExecuteRemainingTime()+currentMinute)/60 + currentHour == jobs[pos+1].getStartHour() 
						&& 
						(jobs[pos].getExecuteRemainingTime()+currentMinute)%60 <= jobs[pos+1].getStartMinute()
						)
					)
					){
					
					//先设置下开始执行的时间
					if(jobs[pos].getFirstExecute() == true){
						jobs[pos].setFirstExecute(false);
						jobs[pos].setExecuteHour(currentHour);
						jobs[pos].setExecuteMinute(currentMinute);
						jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
					}

					jobs[pos].setState(true);
					jobs[pos].setEndHour(currentHour + (jobs[pos].getExecuteRemainingTime() + currentMinute)/60);
					jobs[pos].setEndMinute((jobs[pos].getExecuteRemainingTime() + currentMinute) % 60);
					jobs[pos].setInMemory(false);
					memoryJobCnt--;
					//该作业执行完,要设置当前时间
					currentHour = jobs[tmpPos].getStartHour();
					currentMinute = jobs[tmpPos].getStartMinute();

					
				}else if(
						(  (jobs[pos].getExecuteRemainingTime()+ currentMinute)/60 + currentHour > jobs[tmpPos].getStartHour() 
					   	   || (
						  (jobs[pos].getExecuteRemainingTime()+currentMinute)/60 + currentHour == jobs[pos+1].getStartHour() 
						  && 
						  (jobs[pos].getExecuteRemainingTime()+currentMinute)%60 > jobs[pos+1].getStartMinute()
						)
						)
					){
						
					// B:本次作业执行过程中,将要调入的作业来了
					
					//先设置下开始执行的时间
					if(jobs[pos].getFirstExecute() == true){
						jobs[pos].setFirstExecute(false);
						jobs[pos].setExecuteHour(currentHour);
						jobs[pos].setExecuteMinute(currentMinute);
						jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
					}
		
					int tmpTime = 0;
					if(jobs[tmpPos].getStartHour() == currentHour){
						tmpTime = jobs[tmpPos].getStartMinute() - currentMinute;
					}else{
						tmpTime = (jobs[tmpPos].getStartHour() - 1 - currentHour)*60 + 60 + jobs[tmpPos].getStartMinute() - currentMinute;
					}
					jobs[pos].setExecuteRemainingTime(jobs[pos].getExecuteRemainingTime()-tmpTime);

					currentHour = jobs[tmpPos].getStartHour();
					currentMinute = jobs[tmpPos].getStartMinute();
					

					
				}
				
			}
			
		}

		//计算周转时间、带权周转时间、平均周转时间和平均带权周转时间
		//输出
		System.out.println("作业\t进入时间\t估计运行时间(分钟)\t开始时间\t结束时间\t周转时间(分钟)\t带权周转时间");
		
		double averageTurnOverTime = 0.0;
		double weightedAverageTurnOverTime = 0.0;
		for(int i = 0; i < jobCnt; i++){
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			//计算周转时间
			int tmpTime = (jobs[i].getEndHour() - jobs[i].getStartHour() -1)*60 + 60 + jobs[i].getEndMinute() - jobs[i].getStartMinute();;
			
			jobs[i].setTurnOverTime(tmpTime);
			jobs[i].setWeightedTurnOverTime((jobs[i].getTurnOverTime()+0.0)/(0.0+jobs[i].getExecuteTime()));
			
			averageTurnOverTime += (double)jobs[i].getTurnOverTime();
			weightedAverageTurnOverTime += (double)jobs[i].getWeightedTurnOverTime();
			System.out.println(jobs[i].getName()+"\t"+jobs[i].getStartTime()+"\t\t\t"+jobs[i].getExecuteTime()+"\t\t"+jobs[i].getExecuteStartTime()+"\t\t"+jobs[i].getEndTime()+"\t\t"+
				jobs[i].getTurnOverTime()+"\t\t\t"+jobs[i].getWeightedTurnOverTime());
		
		}
		
		//输出平均周转时间和平均带权周转时间
		System.out.println();
		System.out.println("平均周转时间: "+(averageTurnOverTime/jobCnt)+"分钟");
		System.out.println("平均带权周转时间:"+(weightedAverageTurnOverTime/jobCnt));
		System.out.println("====================================================================================================================");

	}

	public void SJF(int numberOfTracks){

		System.out.println("====================================================================================================================");
		System.out.println("The algorithm is SJF. And the input and output are as follows.");
		System.out.println();
		//存放待调度的作业对象,假设不超过100个作业
		Job[] jobs = new Job[100];//注意这数组中都是引用变量,每个引用变量默认值是null
		int jobCnt = 0;//作业总数记录
		
		
		
		try{
			File in = new File("in.txt");//输入文件
			//File out = new File("out.txt");//输出文件
			BufferedReader br = new BufferedReader(new FileReader(in));//输入流
			//BufferedWriter bw = new BufferedWriter(new FileWriter(out));//输出流

			String line = null;
			//从文件in.txt读入数据
			while((line = br.readLine()) != null){
				
				jobs[jobCnt] = new Job();
				
				//一次读取一行,用空格进行劈开,三个值分别是作业的名称、开始时间、估计运行时间
				String[] splits = line.split(" ");
				jobs[jobCnt].setName(splits[0]);
				jobs[jobCnt].setStartTime(splits[1]);
				jobs[jobCnt].setExecuteTime(Integer.parseInt(splits[2]));
				
				String[] hourMinute = splits[1].split(":");
				jobs[jobCnt].setStartHour(Integer.parseInt(hourMinute[0]));
				jobs[jobCnt].setStartMinute(Integer.parseInt(hourMinute[1]));
				
				jobs[jobCnt].setExecuteRemainingTime(Integer.parseInt(splits[2]));
				
				jobs[jobCnt].setState(false);
				jobs[jobCnt].setInMemory(false);

				jobs[jobCnt].setFirstExecute(true);
			
				//写入文件out.txt
				//bw.write(line,0,line.length());
				//bw.newLine();

				jobCnt++;//每读进来一个作业,作业数目加1
			}

			br.close();//关闭流,否则可能I/O操作失败
			//bw.close();//关闭流,否则可能I/O操作失败
		}catch(Exception e){
			e.printStackTrace();
		}

		Comparator<Job> jobComparator = new JobComparator();//用泛型,否则报-》请使用 -Xlint:unchecked 重新编译
		Arrays.sort(jobs, 0, jobCnt, jobComparator);//按照时间先后给作业排序
		
		

		//到此,数据已经加载完毕,并根据时间的先后顺序进行了排序,下面进入核心算法
		//第一步,每个时间点,调度谁去内存
		//第二步,每个时间点,执行哪个作业

		//当前没有完成的作业分两类,一类是在内存中,一类是不在内存中
		int memoryJobCnt = 0;//内存中作业数目
		int notMemoryJobCnt = jobCnt - getFinishedNumber(jobs, jobCnt) - memoryJobCnt;//当前没有完成且不在内存的作业数目
		
		
		//当前时间
		int currentHour = jobs[0].getStartHour();
		int currentMinute = jobs[0].getStartMinute();
		
		//存在作业没执行的话,就一直执行
		while(getFinishedNumber(jobs, jobCnt) < jobCnt){
			//************************调作业到内存************************
			//选几个还没有完成的、不在内存的作业调入内存。需要明确一点:先来的先调入!
			//最多选(numberOfTracks-memoryJobCnt)=times个已经到来的作业调入内存

			int times = numberOfTracks - memoryJobCnt;
			int tmpCnt = 0;//临时变量,累计本次调入内存的数目,最多达到times个
			
			for(int i =0 ;i < jobCnt; i++){
				if(tmpCnt >= times){break;}//如果调入内存的作业数目大于了本次内存允许调用的数目,终止。若只允许调入1个,那么tmpCnt=1时候终止循环
				if((jobs[i].getStartHour() < currentHour || (jobs[i].getStartHour() == currentHour && jobs[i].getStartMinute() <= currentMinute)) 
						&& jobs[i].getInMemory()==false && jobs[i].getState() == false){
					jobs[i].setInMemory(true);
					notMemoryJobCnt--;
					memoryJobCnt++;
					tmpCnt++;
				}
			}

			//************************从内存选一个作业(准备执行)************************
			//作业已经调入内存,并且此刻内存中必定有没有执行完的作业。因为系统是串行的,必定选择一个作业执行。
			//选择以当前时间为起点运行时间最短的作业执行
			
			int minimumTime = 1000000;//假定最长作业时间不会超过1000000
			int pos = -1;//最短作业对应的数组下标
			for(int i = 0; i < jobCnt ;i++){
				if(jobs[i].getInMemory()==true && jobs[i].getExecuteRemainingTime() < minimumTime){
					minimumTime = jobs[i].getExecuteRemainingTime();
					pos = i;
				}
			}
			
			//************************执行选择的那个作业(开始执行)************************
			//(1)如果当前内存已经满了的话,直接执行完成jobs[pos]即可。
			//(2)如果当前内存未满并且所有未完成的作业都已经调入到了内存,仍然是直接执行完成jobs[pos]即可。
			//(3)如果不是上面两种情况,即内存未满,且存在作业没有调入到内存。这种情况下,要考虑该作业执行过程中,
			//     是否需要调入新作业到内存。由于上面已经完成了作业调入内存的功能,那么这次调入内存的作业也只会有
			//     一个!这一个一定选择此刻尚未完成、未在内存、开始时间最靠前的作业。还需要判断本次作业执行过程中
			//     的时间和将要调入作业的开始时间的关系。
			//     A:本次作业执行完时,将要调入的作业尚未开始。那就需要执行完本次作业。并且把当前时间修改为将要调
			//       入的这个作业的开始时间。
			//     B:本次作业执行过程中,将要调入的作业来了,那就需要把当前时间设置为将要调入的作业的开始时间,并
			//       且设置本次作业的剩余执行时间。
			//     C:本次作业开始执行的时候,将要调入的作业早已经来过了。这种情况直接交给上面的调入内存步骤解决之。
			
			//针对(1)(2)两种情形
			if(memoryJobCnt == numberOfTracks || memoryJobCnt == jobCnt - getFinishedNumber(jobs, jobCnt)){

				//先设置下开始执行的时间
				if(jobs[pos].getFirstExecute() == true){
					jobs[pos].setFirstExecute(false);
					jobs[pos].setExecuteHour(currentHour);
					jobs[pos].setExecuteMinute(currentMinute);
					jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
				}

				jobs[pos].setState(true);
				jobs[pos].setEndHour(currentHour + (jobs[pos].getExecuteRemainingTime() + currentMinute)/60);
				jobs[pos].setEndMinute((jobs[pos].getExecuteRemainingTime() + currentMinute) % 60);
				jobs[pos].setInMemory(false);
				memoryJobCnt--;
		
				//该作业执行完,要设置当前时间
				currentHour = jobs[pos].getEndHour();
				currentMinute = jobs[pos].getEndMinute();

				//再次设置当前时间
				//如果当前内存中的所有作业都执行完之后,还存在内存外尚未执行的作业X,且X的开始时间在当前时间之后,则需要
				//把这样的作业调入内存,那么要把当前时间设置为X的开始时间,为X调入内存做准备。注意这个X就是目前在外存中,
				//且没有完成、且开始时间在目前时间之后,且在所有外存尚未开始执行的作业中开始时间最早。
				if(memoryJobCnt==0 && getFinishedNumber(jobs, jobCnt)<jobCnt){
					for(int i = 0; i < jobCnt; i++){
						if(jobs[i].getInMemory()==false && jobs[i].getState()==false){
							
							if(jobs[i].getStartHour()>currentHour || (jobs[i].getStartHour()==currentHour && jobs[i].getStartMinute()>currentMinute)){
								
								currentHour = jobs[i].getStartHour();						
								currentMinute = jobs[i].getStartMinute();
							}
							break;
						}
					}
				}
				
				
			}else {
				//选中没有完成且不在内存的最先来的作业
				int tmpPos = -1;
				for(int i = 0; i < jobCnt; i++){
					if(jobs[i].getState()==false && jobs[i].getInMemory()==false){
						tmpPos = i;
						
						break;
					}
				}
				
				
				//A:本次作业执行完时,将要调入的作业尚未开始
				if(
					(  (jobs[pos].getExecuteRemainingTime()+ currentMinute)/60 + currentHour < jobs[tmpPos].getStartHour() 
					   || (
						(jobs[pos].getExecuteRemainingTime()+currentMinute)/60 + currentHour == jobs[pos+1].getStartHour() 
						&& 
						(jobs[pos].getExecuteRemainingTime()+currentMinute)%60 <= jobs[pos+1].getStartMinute()
						)
					)
					){
					
					//先设置下开始执行的时间
					if(jobs[pos].getFirstExecute() == true){
						jobs[pos].setFirstExecute(false);
						jobs[pos].setExecuteHour(currentHour);
						jobs[pos].setExecuteMinute(currentMinute);
						jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
					}

					jobs[pos].setState(true);
					jobs[pos].setEndHour(currentHour + (jobs[pos].getExecuteRemainingTime() + currentMinute)/60);
					jobs[pos].setEndMinute((jobs[pos].getExecuteRemainingTime() + currentMinute) % 60);
					jobs[pos].setInMemory(false);
					memoryJobCnt--;
					//该作业执行完,要设置当前时间
					currentHour = jobs[tmpPos].getStartHour();
					currentMinute = jobs[tmpPos].getStartMinute();

					
				}else if(
						(  (jobs[pos].getExecuteRemainingTime()+ currentMinute)/60 + currentHour > jobs[tmpPos].getStartHour() 
					   	   || (
						  (jobs[pos].getExecuteRemainingTime()+currentMinute)/60 + currentHour == jobs[pos+1].getStartHour() 
						  && 
						  (jobs[pos].getExecuteRemainingTime()+currentMinute)%60 > jobs[pos+1].getStartMinute()
						)
						)
					){
						
					// B:本次作业执行过程中,将要调入的作业来了
					
					//先设置下开始执行的时间
					if(jobs[pos].getFirstExecute() == true){
						jobs[pos].setFirstExecute(false);
						jobs[pos].setExecuteHour(currentHour);
						jobs[pos].setExecuteMinute(currentMinute);
						jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
					}
		
					int tmpTime = 0;
					if(jobs[tmpPos].getStartHour() == currentHour){
						tmpTime = jobs[tmpPos].getStartMinute() - currentMinute;
					}else{
						tmpTime = (jobs[tmpPos].getStartHour() - 1 - currentHour)*60 + 60 + jobs[tmpPos].getStartMinute() - currentMinute;
					}
					jobs[pos].setExecuteRemainingTime(jobs[pos].getExecuteRemainingTime()-tmpTime);

					currentHour = jobs[tmpPos].getStartHour();
					currentMinute = jobs[tmpPos].getStartMinute();
					

					
				}
				
			}
			
		}

		//计算周转时间、带权周转时间、平均周转时间和平均带权周转时间
		//输出
		System.out.println("作业\t进入时间\t估计运行时间(分钟)\t开始时间\t结束时间\t周转时间(分钟)\t带权周转时间");
		
		double averageTurnOverTime = 0.0;
		double weightedAverageTurnOverTime = 0.0;
		for(int i = 0; i < jobCnt; i++){
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			//计算周转时间
			int tmpTime = (jobs[i].getEndHour() - jobs[i].getStartHour() -1)*60 + 60 + jobs[i].getEndMinute() - jobs[i].getStartMinute();;
			
			jobs[i].setTurnOverTime(tmpTime);
			jobs[i].setWeightedTurnOverTime((jobs[i].getTurnOverTime()+0.0)/(0.0+jobs[i].getExecuteTime()));
			
			averageTurnOverTime += (double)jobs[i].getTurnOverTime();
			weightedAverageTurnOverTime += (double)jobs[i].getWeightedTurnOverTime();
			System.out.println(jobs[i].getName()+"\t"+jobs[i].getStartTime()+"\t\t\t"+jobs[i].getExecuteTime()+"\t\t"+jobs[i].getExecuteStartTime()+"\t\t"+jobs[i].getEndTime()+"\t\t"+
				jobs[i].getTurnOverTime()+"\t\t\t"+jobs[i].getWeightedTurnOverTime());
		
		}
		
		//输出平均周转时间和平均带权周转时间
		System.out.println();
		System.out.println("平均周转时间: "+(averageTurnOverTime/jobCnt)+"分钟");
		System.out.println("平均带权周转时间:"+(weightedAverageTurnOverTime/jobCnt));
		System.out.println("====================================================================================================================");
	}
	
	public void HRRN(int numberOfTracks){
		System.out.println("====================================================================================================================");
		System.out.println("The algorithm is HRRN. And the input and output are as follows.");
		System.out.println();
		//存放待调度的作业对象,假设不超过100个作业
		Job[] jobs = new Job[100];//注意这数组中都是引用变量,每个引用变量默认值是null
		int jobCnt = 0;//作业总数记录
		
		
		
		try{
			File in = new File("in.txt");//输入文件
			//File out = new File("out.txt");//输出文件
			BufferedReader br = new BufferedReader(new FileReader(in));//输入流
			//BufferedWriter bw = new BufferedWriter(new FileWriter(out));//输出流

			String line = null;
			//从文件in.txt读入数据
			while((line = br.readLine()) != null){
				
				jobs[jobCnt] = new Job();
				
				//一次读取一行,用空格进行劈开,三个值分别是作业的名称、开始时间、估计运行时间
				String[] splits = line.split(" ");
				jobs[jobCnt].setName(splits[0]);
				jobs[jobCnt].setStartTime(splits[1]);
				jobs[jobCnt].setExecuteTime(Integer.parseInt(splits[2]));
				
				String[] hourMinute = splits[1].split(":");
				jobs[jobCnt].setStartHour(Integer.parseInt(hourMinute[0]));
				jobs[jobCnt].setStartMinute(Integer.parseInt(hourMinute[1]));
				
				jobs[jobCnt].setExecuteRemainingTime(Integer.parseInt(splits[2]));
				
				jobs[jobCnt].setState(false);
				jobs[jobCnt].setInMemory(false);

				jobs[jobCnt].setFirstExecute(true);
			
				//写入文件out.txt
				//bw.write(line,0,line.length());
				//bw.newLine();

				jobCnt++;//每读进来一个作业,作业数目加1
			}

			br.close();//关闭流,否则可能I/O操作失败
			//bw.close();//关闭流,否则可能I/O操作失败
		}catch(Exception e){
			e.printStackTrace();
		}

		Comparator<Job> jobComparator = new JobComparator();//用泛型,否则报-》请使用 -Xlint:unchecked 重新编译
		Arrays.sort(jobs, 0, jobCnt, jobComparator);//按照时间先后给作业排序
		
		

		//到此,数据已经加载完毕,并根据时间的先后顺序进行了排序,下面进入核心算法
		//第一步,每个时间点,调度谁去内存
		//第二步,每个时间点,执行哪个作业

		//当前没有完成的作业分两类,一类是在内存中,一类是不在内存中
		int memoryJobCnt = 0;//内存中作业数目
		int notMemoryJobCnt = jobCnt - getFinishedNumber(jobs, jobCnt) - memoryJobCnt;//当前没有完成且不在内存的作业数目
		
		
		//当前时间
		int currentHour = jobs[0].getStartHour();
		int currentMinute = jobs[0].getStartMinute();
		
		//存在作业没执行的话,就一直执行
		while(getFinishedNumber(jobs, jobCnt) < jobCnt){
			//************************调作业到内存************************
			//选几个还没有完成的、不在内存的作业调入内存。需要明确一点:先来的先调入!
			//最多选(numberOfTracks-memoryJobCnt)=times个已经到来的作业调入内存

			int times = numberOfTracks - memoryJobCnt;
			int tmpCnt = 0;//临时变量,累计本次调入内存的数目,最多达到times个
			
			for(int i =0 ;i < jobCnt; i++){
				if(tmpCnt >= times){break;}//如果调入内存的作业数目大于了本次内存允许调用的数目,终止。若只允许调入1个,那么tmpCnt=1时候终止循环
				if((jobs[i].getStartHour() < currentHour || (jobs[i].getStartHour() == currentHour && jobs[i].getStartMinute() <= currentMinute)) 
						&& jobs[i].getInMemory()==false && jobs[i].getState() == false){
					jobs[i].setInMemory(true);
					notMemoryJobCnt--;
					memoryJobCnt++;
					tmpCnt++;
				}
			}

			//************************【【算法核心】】从内存选一个作业(准备执行)************************
			//作业已经调入内存,并且此刻内存中必定有没有执行完的作业。因为系统是串行的,必定选择一个作业执行。
			//选择最高响应比的作业执行
			
			double responseRatio = -1.0;//响应比=作业等待时间/作业处理时间
			int pos = -1;//最高响应比作业对应的数组下标
			for(int i = 0; i < jobCnt ;i++){
				int waitTime = (currentHour - jobs[i].getStartHour() - 1)*60 + 60 + currentMinute - jobs[i].getStartMinute();
				if(jobs[i].getInMemory()==true && (double)waitTime/(double)jobs[i].getExecuteRemainingTime() > responseRatio){
					responseRatio = (double)waitTime/(double)jobs[i].getExecuteRemainingTime();
					pos = i;
				}
			}
			
			//************************执行选择的那个作业(开始执行)************************
			//(1)如果当前内存已经满了的话,直接执行完成jobs[pos]即可。
			//(2)如果当前内存未满并且所有未完成的作业都已经调入到了内存,仍然是直接执行完成jobs[pos]即可。
			//(3)如果不是上面两种情况,即内存未满,且存在作业没有调入到内存。这种情况下,要考虑该作业执行过程中,
			//     是否需要调入新作业到内存。由于上面已经完成了作业调入内存的功能,那么这次调入内存的作业也只会有
			//     一个!这一个一定选择此刻尚未完成、未在内存、开始时间最靠前的作业。还需要判断本次作业执行过程中
			//     的时间和将要调入作业的开始时间的关系。
			//     A:本次作业执行完时,将要调入的作业尚未开始。那就需要执行完本次作业。并且把当前时间修改为将要调
			//       入的这个作业的开始时间。
			//     B:本次作业执行过程中,将要调入的作业来了,那就需要把当前时间设置为将要调入的作业的开始时间,并
			//       且设置本次作业的剩余执行时间。
			//     C:本次作业开始执行的时候,将要调入的作业早已经来过了。这种情况直接交给上面的调入内存步骤解决之。
			
			//针对(1)(2)两种情形
			if(memoryJobCnt == numberOfTracks || memoryJobCnt == jobCnt - getFinishedNumber(jobs, jobCnt)){

				//先设置下开始执行的时间
				if(jobs[pos].getFirstExecute() == true){
					jobs[pos].setFirstExecute(false);
					jobs[pos].setExecuteHour(currentHour);
					jobs[pos].setExecuteMinute(currentMinute);
					jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
				}

				jobs[pos].setState(true);
				jobs[pos].setEndHour(currentHour + (jobs[pos].getExecuteRemainingTime() + currentMinute)/60);
				jobs[pos].setEndMinute((jobs[pos].getExecuteRemainingTime() + currentMinute) % 60);
				jobs[pos].setInMemory(false);
				memoryJobCnt--;
		
				//该作业执行完,要设置当前时间
				currentHour = jobs[pos].getEndHour();
				currentMinute = jobs[pos].getEndMinute();

				//再次设置当前时间
				//如果当前内存中的所有作业都执行完之后,还存在内存外尚未执行的作业X,且X的开始时间在当前时间之后,则需要
				//把这样的作业调入内存,那么要把当前时间设置为X的开始时间,为X调入内存做准备。注意这个X就是目前在外存中,
				//且没有完成、且开始时间在目前时间之后,且在所有外存尚未开始执行的作业中开始时间最早。
				if(memoryJobCnt==0 && getFinishedNumber(jobs, jobCnt)<jobCnt){
					for(int i = 0; i < jobCnt; i++){
						if(jobs[i].getInMemory()==false && jobs[i].getState()==false){
							
							if(jobs[i].getStartHour()>currentHour || (jobs[i].getStartHour()==currentHour && jobs[i].getStartMinute()>currentMinute)){
								
								currentHour = jobs[i].getStartHour();						
								currentMinute = jobs[i].getStartMinute();
							}
							break;
						}
					}
				}
				
				
			}else {
				//选中没有完成且不在内存的最先来的作业
				int tmpPos = -1;
				for(int i = 0; i < jobCnt; i++){
					if(jobs[i].getState()==false && jobs[i].getInMemory()==false){
						tmpPos = i;
						
						break;
					}
				}
				
				
				//A:本次作业执行完时,将要调入的作业尚未开始
				if(
					(  (jobs[pos].getExecuteRemainingTime()+ currentMinute)/60 + currentHour < jobs[tmpPos].getStartHour() 
					   || (
						(jobs[pos].getExecuteRemainingTime()+currentMinute)/60 + currentHour == jobs[pos+1].getStartHour() 
						&& 
						(jobs[pos].getExecuteRemainingTime()+currentMinute)%60 <= jobs[pos+1].getStartMinute()
						)
					)
					){
					
					//先设置下开始执行的时间
					if(jobs[pos].getFirstExecute() == true){
						jobs[pos].setFirstExecute(false);
						jobs[pos].setExecuteHour(currentHour);
						jobs[pos].setExecuteMinute(currentMinute);
						jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
					}

					jobs[pos].setState(true);
					jobs[pos].setEndHour(currentHour + (jobs[pos].getExecuteRemainingTime() + currentMinute)/60);
					jobs[pos].setEndMinute((jobs[pos].getExecuteRemainingTime() + currentMinute) % 60);
					jobs[pos].setInMemory(false);
					memoryJobCnt--;
					//该作业执行完,要设置当前时间
					currentHour = jobs[tmpPos].getStartHour();
					currentMinute = jobs[tmpPos].getStartMinute();

					
				}else if(
						(  (jobs[pos].getExecuteRemainingTime()+ currentMinute)/60 + currentHour > jobs[tmpPos].getStartHour() 
					   	   || (
						  (jobs[pos].getExecuteRemainingTime()+currentMinute)/60 + currentHour == jobs[pos+1].getStartHour() 
						  && 
						  (jobs[pos].getExecuteRemainingTime()+currentMinute)%60 > jobs[pos+1].getStartMinute()
						)
						)
					){
						
					// B:本次作业执行过程中,将要调入的作业来了
					
					//先设置下开始执行的时间
					if(jobs[pos].getFirstExecute() == true){
						jobs[pos].setFirstExecute(false);
						jobs[pos].setExecuteHour(currentHour);
						jobs[pos].setExecuteMinute(currentMinute);
						jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());
					}
		
					int tmpTime = 0;
					if(jobs[tmpPos].getStartHour() == currentHour){
						tmpTime = jobs[tmpPos].getStartMinute() - currentMinute;
					}else{
						tmpTime = (jobs[tmpPos].getStartHour() - 1 - currentHour)*60 + 60 + jobs[tmpPos].getStartMinute() - currentMinute;
					}
					jobs[pos].setExecuteRemainingTime(jobs[pos].getExecuteRemainingTime()-tmpTime);

					currentHour = jobs[tmpPos].getStartHour();
					currentMinute = jobs[tmpPos].getStartMinute();
					

					
				}
				
			}
			
		}

		//计算周转时间、带权周转时间、平均周转时间和平均带权周转时间
		//输出
		System.out.println("作业\t进入时间\t估计运行时间(分钟)\t开始时间\t结束时间\t周转时间(分钟)\t带权周转时间");
		
		double averageTurnOverTime = 0.0;
		double weightedAverageTurnOverTime = 0.0;
		for(int i = 0; i < jobCnt; i++){
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			//计算周转时间
			int tmpTime = (jobs[i].getEndHour() - jobs[i].getStartHour() -1)*60 + 60 + jobs[i].getEndMinute() - jobs[i].getStartMinute();;
			
			jobs[i].setTurnOverTime(tmpTime);
			jobs[i].setWeightedTurnOverTime((jobs[i].getTurnOverTime()+0.0)/(0.0+jobs[i].getExecuteTime()));
			
			averageTurnOverTime += (double)jobs[i].getTurnOverTime();
			weightedAverageTurnOverTime += (double)jobs[i].getWeightedTurnOverTime();
			System.out.println(jobs[i].getName()+"\t"+jobs[i].getStartTime()+"\t\t\t"+jobs[i].getExecuteTime()+"\t\t"+jobs[i].getExecuteStartTime()+"\t\t"+jobs[i].getEndTime()+"\t\t"+
				jobs[i].getTurnOverTime()+"\t\t\t"+jobs[i].getWeightedTurnOverTime());
		
		}
		
		//输出平均周转时间和平均带权周转时间
		System.out.println();
		System.out.println("平均周转时间: "+(averageTurnOverTime/jobCnt)+"分钟");
		System.out.println("平均带权周转时间:"+(weightedAverageTurnOverTime/jobCnt));
		System.out.println("====================================================================================================================");
	}
	
	

	public void singleSJF(){
		System.out.println("====================================================================================================================");
		System.out.println("The algorithm is SJF. And the input and output are as follows.");
		System.out.println();
		//存放待调度的作业对象,假设不超过100个作业
		Job[] jobs = new Job[100];//注意这数组中都是引用变量,每个引用变量默认值是null
		int jobCnt = 0;//作业总数记录
		
		
		
		try{
			File in = new File("in.txt");//输入文件
			//File out = new File("out.txt");//输出文件
			BufferedReader br = new BufferedReader(new FileReader(in));//输入流
			//BufferedWriter bw = new BufferedWriter(new FileWriter(out));//输出流

			String line = null;
			//从文件in.txt读入数据
			while((line = br.readLine()) != null){
				
				jobs[jobCnt] = new Job();
				
				//一次读取一行,用空格进行劈开,三个值分别是作业的名称、开始时间、估计运行时间
				String[] splits = line.split(" ");
				jobs[jobCnt].setName(splits[0]);
				jobs[jobCnt].setStartTime(splits[1]);
				jobs[jobCnt].setExecuteTime(Integer.parseInt(splits[2]));
				
				String[] hourMinute = splits[1].split(":");
				jobs[jobCnt].setStartHour(Integer.parseInt(hourMinute[0]));
				jobs[jobCnt].setStartMinute(Integer.parseInt(hourMinute[1]));
				
				jobs[jobCnt].setExecuteRemainingTime(Integer.parseInt(splits[2]));
				
				jobs[jobCnt].setState(false);
				jobs[jobCnt].setInMemory(false);

				jobs[jobCnt].setFirstExecute(true);
			
				//写入文件out.txt
				//bw.write(line,0,line.length());
				//bw.newLine();

				jobCnt++;//每读进来一个作业,作业数目加1
			}

			br.close();//关闭流,否则可能I/O操作失败
			//bw.close();//关闭流,否则可能I/O操作失败
		}catch(Exception e){
			e.printStackTrace();
		}

		Comparator<Job> jobComparator = new JobComparator();//用泛型,否则报-》请使用 -Xlint:unchecked 重新编译
		Arrays.sort(jobs, 0, jobCnt, jobComparator);//按照时间先后给作业排序
		
		int currentHour = jobs[0].getStartHour();//当前时间对应的小时
		int currentMinute = jobs[0].getStartMinute();//当前时间对应的分钟		

		//单道批处理系统下,最短作业调度,每次在尚未完成的作业中选时间最短的执行,要注意在当前时间之前已经到达
		while(getFinishedNumber(jobs, jobCnt) < jobCnt){
			int pos = -1;//选择要执行的作业的下标
			int minimumTime = 1000000;//假定最长时间不超过1000000
			//先选一个当前时间及之前到来的尚未执行的作业中最短时间的作业
			for(int i = 0; i < jobCnt; i++){
				if(jobs[i].getState()==false && jobs[i].getExecuteTime()<minimumTime && 
					(jobs[i].getStartHour()<currentHour || (jobs[i].getStartHour()==currentHour && jobs[i].getStartMinute()<=currentMinute)) ){
					minimumTime = jobs[i].getExecuteTime();
					pos = i;
				}
			}
			//执行这个最短作业
			
			jobs[pos].setState(true);	
			jobs[pos].setEndHour(currentHour+(currentMinute+jobs[pos].getExecuteTime())/60);
			jobs[pos].setEndMinute((currentMinute+jobs[pos].getExecuteTime())%60);
			jobs[pos].setExecuteHour(currentHour);
			jobs[pos].setExecuteMinute(currentMinute);
			jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());			

			//更新当前时间
			//注意:如果此作业执行完之后,其他作业都没有开始的,当前时间应该设为尚未开始作业的最早时间
			currentHour = jobs[pos].getEndHour();
			currentMinute = jobs[pos].getEndMinute();
			
			
			//寻找最早开始的作业
			for(int i = 0; i < jobCnt; i++){
				if(jobs[i].getState()==false){
					int tmpHour = jobs[i].getStartHour();
					int tmpMinute = jobs[i].getStartMinute();
					if(tmpHour>currentHour || (tmpHour==currentHour && tmpMinute>currentMinute)){
						currentHour = tmpHour;
						currentMinute = tmpMinute;
					}
					break;
				}
			}
			
			
		}
		
		//计算周转时间、带权周转时间、平均周转时间和平均带权周转时间
		//输出
		System.out.println("作业\t进入时间\t估计运行时间(分钟)\t开始时间\t结束时间\t周转时间(分钟)\t带权周转时间");
		
		double averageTurnOverTime = 0.0;
		double weightedAverageTurnOverTime = 0.0;
		for(int i = 0; i < jobCnt; i++){
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			//计算周转时间
			int tmpTime = (jobs[i].getEndHour() - jobs[i].getStartHour() -1)*60 + 60 + jobs[i].getEndMinute() - jobs[i].getStartMinute();;
			
			jobs[i].setTurnOverTime(tmpTime);
			jobs[i].setWeightedTurnOverTime((jobs[i].getTurnOverTime()+0.0)/(0.0+jobs[i].getExecuteTime()));
			
			averageTurnOverTime += (double)jobs[i].getTurnOverTime();
			weightedAverageTurnOverTime += (double)jobs[i].getWeightedTurnOverTime();
			System.out.println(jobs[i].getName()+"\t"+jobs[i].getStartTime()+"\t\t\t"+jobs[i].getExecuteTime()+"\t\t"+jobs[i].getExecuteStartTime()+"\t\t"+jobs[i].getEndTime()+"\t\t"+
				jobs[i].getTurnOverTime()+"\t\t\t"+jobs[i].getWeightedTurnOverTime());
		
		}
		
		//输出平均周转时间和平均带权周转时间
		System.out.println();
		System.out.println("平均周转时间: "+(averageTurnOverTime/jobCnt)+"分钟");
		System.out.println("平均带权周转时间:"+(weightedAverageTurnOverTime/jobCnt));
		System.out.println("====================================================================================================================");
	

		
	}
	
	public void singleHRRN(){
		System.out.println("====================================================================================================================");
		System.out.println("The algorithm is HRRN. And the input and output are as follows.");
		System.out.println();
		//存放待调度的作业对象,假设不超过100个作业
		Job[] jobs = new Job[100];//注意这数组中都是引用变量,每个引用变量默认值是null
		int jobCnt = 0;//作业总数记录
		
		
		
		try{
			File in = new File("in.txt");//输入文件
			//File out = new File("out.txt");//输出文件
			BufferedReader br = new BufferedReader(new FileReader(in));//输入流
			//BufferedWriter bw = new BufferedWriter(new FileWriter(out));//输出流

			String line = null;
			//从文件in.txt读入数据
			while((line = br.readLine()) != null){
				
				jobs[jobCnt] = new Job();
				
				//一次读取一行,用空格进行劈开,三个值分别是作业的名称、开始时间、估计运行时间
				String[] splits = line.split(" ");
				jobs[jobCnt].setName(splits[0]);
				jobs[jobCnt].setStartTime(splits[1]);
				jobs[jobCnt].setExecuteTime(Integer.parseInt(splits[2]));
				
				String[] hourMinute = splits[1].split(":");
				jobs[jobCnt].setStartHour(Integer.parseInt(hourMinute[0]));
				jobs[jobCnt].setStartMinute(Integer.parseInt(hourMinute[1]));
				
				jobs[jobCnt].setExecuteRemainingTime(Integer.parseInt(splits[2]));
				
				jobs[jobCnt].setState(false);
				jobs[jobCnt].setInMemory(false);

				jobs[jobCnt].setFirstExecute(true);
			
				//写入文件out.txt
				//bw.write(line,0,line.length());
				//bw.newLine();

				jobCnt++;//每读进来一个作业,作业数目加1
			}

			br.close();//关闭流,否则可能I/O操作失败
			//bw.close();//关闭流,否则可能I/O操作失败
		}catch(Exception e){
			e.printStackTrace();
		}

		Comparator<Job> jobComparator = new JobComparator();//用泛型,否则报-》请使用 -Xlint:unchecked 重新编译
		Arrays.sort(jobs, 0, jobCnt, jobComparator);//按照时间先后给作业排序
		
		int currentHour = jobs[0].getStartHour();//当前时间对应的小时
		int currentMinute = jobs[0].getStartMinute();//当前时间对应的分钟		

		//单道批处理系统下,最高响应比调度,每次在尚未完成的作业中选最高响应比的执行,要注意在当前时间之前已经到达
		while(getFinishedNumber(jobs, jobCnt) < jobCnt){
			int pos = -1;//选择要执行的作业的下标
			double responseRatio = -1.0;
			//先选一个当前时间及之前到来的尚未执行的作业中最高响应比的作业
			for(int i = 0; i < jobCnt; i++){
				//最高响应比简化下----》》》等待时间/处理时间
				int waitTime = (currentHour - jobs[i].getStartHour() - 1)*60 + 60 + currentMinute - jobs[i].getStartMinute();
				if(jobs[i].getState()==false && (double)waitTime/(double)jobs[i].getExecuteTime()>responseRatio && 
					(jobs[i].getStartHour()<currentHour || (jobs[i].getStartHour()==currentHour && jobs[i].getStartMinute()<=currentMinute)) ){
					responseRatio = (double)waitTime/(double)jobs[i].getExecuteTime();
					pos = i;
				}
			}
			//执行这个最高响应比作业
			
			jobs[pos].setState(true);	
			jobs[pos].setEndHour(currentHour+(currentMinute+jobs[pos].getExecuteTime())/60);
			jobs[pos].setEndMinute((currentMinute+jobs[pos].getExecuteTime())%60);
			jobs[pos].setExecuteHour(currentHour);
			jobs[pos].setExecuteMinute(currentMinute);
			jobs[pos].setExecuteStartTime(jobs[pos].getExecuteHour()+":"+jobs[pos].getExecuteMinute());			

			//更新当前时间
			//注意:如果此作业执行完之后,其他作业都没有开始的,当前时间应该设为尚未开始作业的最早时间
			currentHour = jobs[pos].getEndHour();
			currentMinute = jobs[pos].getEndMinute();
			
			
			//寻找最早开始的作业
			for(int i = 0; i < jobCnt; i++){
				if(jobs[i].getState()==false){
					int tmpHour = jobs[i].getStartHour();
					int tmpMinute = jobs[i].getStartMinute();
					if(tmpHour>currentHour || (tmpHour==currentHour && tmpMinute>currentMinute)){
						currentHour = tmpHour;
						currentMinute = tmpMinute;
					}
					break;
				}
			}
			
			
		}
		
		//计算周转时间、带权周转时间、平均周转时间和平均带权周转时间
		//输出
		System.out.println("作业\t进入时间\t估计运行时间(分钟)\t开始时间\t结束时间\t周转时间(分钟)\t带权周转时间");
		
		double averageTurnOverTime = 0.0;
		double weightedAverageTurnOverTime = 0.0;
		for(int i = 0; i < jobCnt; i++){
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			
			jobs[i].setEndTime(jobs[i].getEndHour()+":"+jobs[i].getEndMinute());
			//计算周转时间
			int tmpTime = (jobs[i].getEndHour() - jobs[i].getStartHour() -1)*60 + 60 + jobs[i].getEndMinute() - jobs[i].getStartMinute();;
			
			jobs[i].setTurnOverTime(tmpTime);
			jobs[i].setWeightedTurnOverTime((jobs[i].getTurnOverTime()+0.0)/(0.0+jobs[i].getExecuteTime()));
			
			averageTurnOverTime += (double)jobs[i].getTurnOverTime();
			weightedAverageTurnOverTime += (double)jobs[i].getWeightedTurnOverTime();
			System.out.println(jobs[i].getName()+"\t"+jobs[i].getStartTime()+"\t\t\t"+jobs[i].getExecuteTime()+"\t\t"+jobs[i].getExecuteStartTime()+"\t\t"+jobs[i].getEndTime()+"\t\t"+
				jobs[i].getTurnOverTime()+"\t\t\t"+jobs[i].getWeightedTurnOverTime());
		
		}
		
		//输出平均周转时间和平均带权周转时间
		System.out.println();
		System.out.println("平均周转时间: "+(averageTurnOverTime/jobCnt)+"分钟");
		System.out.println("平均带权周转时间:"+(weightedAverageTurnOverTime/jobCnt));
		System.out.println("====================================================================================================================");
	

	}

	//计算已经完成的作业数目
	public int getFinishedNumber(Job[] jobs, int jobCnt){

		int num = 0;
		for(int i = 0; i < jobCnt; i++){
			if(jobs[i].getState() == true){
				num ++;
			}
		}
		return num;
	}
}

Job.java

import java.util.Comparator;

public class Job{

	private String name;//作业名称
	private String startTime;//作业进入时间
	private String endTime;//作业完成时间
	
	private int executeTime;//作业估计运行时间
	private int executeRemainingTime;//作业估计运行时间的剩余时间
	

	private int startHour;//进入时间对应的小时
	private int startMinute;//进入时间对应的分钟

	private int executeHour;//开始执行时间对应的小时
	private int executeMinute;//开始执行时间对应的分钟
	private String executeStartTime;//开始执行的时间

	private int endHour;//结束时间对应的小时
	private int endMinute;//结束时间对应的分钟
	

	private int turnOverTime;//周转时间,用分钟记
	private double weightedTurnOverTime;//带权周转时间
	
	private boolean state;//标记该作业是否执行完成
	private boolean inMemory;//标记作业是否在内存

	private boolean firstExecute;//标记是否是第一次执行

	public void setName(String name){
		this.name = name;
	}	
	public String getName(){
		return this.name;
	}

	public void setStartTime(String startTime){
		this.startTime = startTime;
	}	
	public String getStartTime(){
		return this.startTime;
	}

	public void setEndTime(String endTime){
		this.endTime = endTime;
	}	
	public String getEndTime(){
		return this.endTime;
	}

	public void setExecuteTime(int executeTime){
		this.executeTime = executeTime;
	}	
	public int getExecuteTime(){
		return this.executeTime;
	}

	public void setExecuteRemainingTime(int executeRemainingTime){
		this.executeRemainingTime = executeRemainingTime;
	}	
	public int getExecuteRemainingTime(){
		return this.executeRemainingTime;
	}

	public void setStartHour(int startHour){
		this.startHour = startHour;
	}
	public int getStartHour(){
		return this.startHour;
	}

	public void setStartMinute(int startMinute){
		this.startMinute = startMinute;
	}
	public int getStartMinute(){
		return this.startMinute;
	}

	public void setEndHour(int endHour){
		this.endHour = endHour;
	}
	public int getEndHour(){
		return this.endHour;
	}

	public void setEndMinute(int endMinute){
		this.endMinute = endMinute;
	}
	public int getEndMinute(){
		return this.endMinute;
	}
	
	public void setTurnOverTime(int turnOverTime){
		this.turnOverTime = turnOverTime;
	}
	public int getTurnOverTime(){
		return this.turnOverTime;
	}

	public void setWeightedTurnOverTime(double weightedTurnOverTime){
		this.weightedTurnOverTime = weightedTurnOverTime;
	}
	public double getWeightedTurnOverTime(){
		return this.weightedTurnOverTime;
	}

	public void setState(boolean state){
		this.state = state;
	}
	public boolean getState(){
		return this.state;
	}

	public void setInMemory(boolean inMemory){
		this.inMemory = inMemory;
	}
	public boolean getInMemory(){
		return this.inMemory;
	}

	public void setExecuteHour(int executeHour){
		this.executeHour = executeHour;
	}
	public int getExecuteHour(){
		return this.executeHour;
	}

	public void setExecuteMinute(int executeMinute){
		this.executeMinute = executeMinute;
	}
	public int getExecuteMinute(){
		return this.executeMinute;
	}

	public void setFirstExecute(boolean firstExecute){
		this.firstExecute = firstExecute;
	}
	public boolean getFirstExecute(){
		return this.firstExecute;
	}

	public void setExecuteStartTime(String executeStartTime){
		this.executeStartTime = executeStartTime;
	}
	public String getExecuteStartTime(){
		return this.executeStartTime;
	}

	
	//测试
	/*
	public static void main(String[] args){
		Job job = new Job();
		job.setName("job");
		job.setStartTime("8:00");
		job.setEndTime("10:00");
		job.setCurrentTime("8:00");
		job.setExecuteTime(50);
		job.setExecuteRemainingTime(50);
		System.out.println(job.getName()+" "+job.getStartTime()+" "+job.getEndTime()+" "+
			job.getCurrentTime()+" "+job.getExecuteTime()+" "+job.getExecuteRemainingTime());
	
		
	}
	*/

}

//比较器实现Job对象排序,根据时间先后顺序进行
class JobComparator implements Comparator<Job>{

	public int compare(Job job1, Job job2){
		
		if(job1.getStartHour() < job2.getStartHour()){
			return -1;
		}else if(job1.getStartHour() > job2.getStartHour()){
			return 1;
		}else{
			if(job1.getStartMinute() < job2.getStartMinute()){
				return -1;
			}else if(job1.getStartMinute() > job2.getStartMinute()){
				return 1;
			}else{
				return 0;
			}
		}
	}
}

实验测试

因为代码是Java实现的,所以电脑上要先有JDK!!!
首先把源代码文件和数据读入文件放在同一个文件夹中:
在这里插入图片描述
in.txt数据:
job1 8:00 120
job2 8:50 50
job3 9:00 10
job4 9:50 20

单道批处理系统作业调度测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

多道批处理系统作业调度测试(在上面的基础上更改数据了)

in.txt数据更换如下:
job1 10:00 30
job2 10:05 20
job3 10:10 5
job4 10:20 10

测试结果如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ccnuacmhdu/article/details/82825844