一、简介
1、此为计算机系统能力实训选题之一,具体实现时间片轮转算法、优先级算法、高响应比算法和多级反馈队列算法这四种调度算法。四种算法的知识点不多赘述。
2、不同于之前的控制台输入,这次我受一位博主启发,使用GUI功能模拟了四种调度算法的动态过程,与动画还是有很大差距,但相比之前更加形象直观,。
3、本想实现更友好化的界面,奈何能力、时间有限,很多想法没能实现,比如如何加上滚动条,给优先级算法和多级反馈队列算法加上到达时间等等,欢迎完善。
二、核心函数代码
1、时间片轮转算法
public static void startRRSimulation()
{
isStopScheduling = false;
//更新界面操作必须借助多线程来实现
new Thread(new Runnable()
{
@Override
public void run()
{
//当前内存中还留有进程未执
while(currentPCBsNum!=0 && !isStopScheduling)
{
LinkedList<PCB> queue1 = PCBsQueues[3].getQueue();//UnArrive队列
LinkedList<PCB> queue3 = PCBsQueues[4].getQueue();//Running队列
Collections.sort(queue1, new compareArrive());//对UnArrive队列按照到达时间升序排队
textArea.setText(String.valueOf(nowTime));//用于在时钟对应位置展示此时的nowTime,即当前时间
boolean flag = true;//标志
while((queue1.size()>0)&&(flag)) {//UnArrive队列非空且flag为true
flag=false;//设置flag为false
PCB pcb1 = queue1.element();//获取UnArrive队列第一个进程
if(pcb1.getarriveTime()<=nowTime) {//判断进程是否已经到达
queue1.poll(); //若到达,则将进程从UnArrive队列删除
pcb1.setStatus("Ready"); //设置进程状态为Ready
queue3.offer(pcb1); //将进程添加到Ready队列
flag=true; //flag设为true,表示进程进入过该if选择语句
} //因为UnArrive队列已经按照到达时间排序,所以一旦UnArrive队列队列首个元素都未到达,后边进程不必再判断,无法进入if选择语句,flag无法变为true,while循环结束
}
PCBsQueues[3].setQueue(queue1);//将UnArrive队列放回队列组
PCBsQueues[4].setQueue(queue3);//将Running队列放回队列组
showPCBQueues(PCBsQueues);//展示进程剩余服务时间变化
if(queue3.size()>0) //Running队列不为空
{
PCB pcb3=queue3.element();//获取Running队列第一个进程
pcb3.setStatus("Running");
PCBsQueues[3].setQueue(queue1);//将UnArrive队列放回队列组
PCBsQueues[4].setQueue(queue3);//将Running队列放回队列组
showPCBQueues(PCBsQueues);//展示进程剩余服务时间变化
int pid=pcb3.getPid();//获取进程ID
float temp3=pcb3.getSurplusServeTime()-1;//再减去等待时间,即为该进程的已运行时间
pcb3.setSurplusServeTime(temp3);//设置进程的剩余服务时间
try
{
Thread.sleep((int)(1 * 5000));//每次循环sleep一个时间片的时间
}
catch (InterruptedException e)
{
e.printStackTrace();
}
if(temp3<=0) {//剩余服务时间小于0,即运行结束
queue3.poll();//删除该进程
pidsUsed[pid] = 0;//设置该进程ID未使用
currentPCBsNum--;//进程数减1
}else {
pcb3.setStatus("Ready");
queue3.poll();//删除Running队列第一个进程
queue3.offer(pcb3);//添加至队尾
showPCBQueues(PCBsQueues);//展示进程剩余服务时间变化
}
}else {
try
{
Thread.sleep((int)(1 * 5000));//每次循环sleep一个时间片的时间
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
PCBsQueues[3].setQueue(queue1);//将UnArrive队列放回队列组
PCBsQueues[4].setQueue(queue3);//将Running队列放回队列组
showPCBQueues(PCBsQueues);//展示进程剩余服务时间变化
nowTime=nowTime+1;//当前时间加1,表示时钟走过一秒
textArea.setText(String.valueOf(nowTime));//用于在时钟对应位置展示此时的nowTime,即当前时间
}
initMemory();//初始化内存
showPCBQueues(PCBsQueues);
//有进程均执行完成,进程调度完
JOptionPane.showMessageDialog(frame, "进程调度完成!");
//frame.dispose();
}
}).start();
}
2、优先级调度算法
public static void startPSA()
{
isStopScheduling = false;
//更新界面操作必须借助多线程来实现
new Thread(new Runnable()
{
@Override
public void run()
{
//当前内存中还留有进程未执行
while(currentPCBsNum!=0 && !isStopScheduling)
{
textArea.setText(String.valueOf(nowTime));//用于在时钟对应位置展示此时的nowTime,即当前时间
for(int i = PCBsQueues.length - 1; i >= 0; i--)//每次按优先级由高到低取队列组的队列
{
LinkedList<PCB> queue = PCBsQueues[i].getQueue();
if (queue.size() > 0)//队列不为空
{
PCB pcb = queue.element(); //读取该队列首个PCB
pcb.setStatus("Running");//设置状态为Running
showPCBQueues(PCBsQueues);
int pid = pcb.getPid();//获得进程ID
int priority = pcb.getPriority();//获得进程优先级
float SurplusServeTime=pcb.getSurplusServeTime();//获得进程剩余服务时间
priority = priority-1;//优先级减1
if(SurplusServeTime>1) {//剩余服务时间大于1个时间片
try
{
Thread.sleep((int)(1 * 2000));//每次循环sleep一个时间片的时间
}
catch (InterruptedException e)
{
e.printStackTrace();
}
SurplusServeTime--;//剩余服务时间减1
pcb.setSurplusServeTime(SurplusServeTime);//更新进程的剩余服务时间
}
else {//剩余服务时间不止一个时间片
try
{
Thread.sleep((int)(SurplusServeTime * 2000));//每次循环sleep一个时间片的时间
}
catch (InterruptedException e)
{
e.printStackTrace();
}
//移除该队列的首个PCB
queue.poll();
pidsUsed[pid] = 0;//更新进程使用数组
currentPCBsNum--;//内存中进程数减1
}
nowTime++;//时钟+1,同步变化
textArea.setText(String.valueOf(nowTime));//用于在时钟对应位置展示此时的nowTime,即当前时间
break;
}
}
// nowTime++;
}
initMemory();
showPCBQueues(PCBsQueues);
//有进程均执行完成,进程调度完
JOptionPane.showMessageDialog(frame, "进程调度完成!");
//frame.dispose();
}
}).start();
}
3、高响应比调度算法
public static void startHRRN()
{
isStopScheduling = false;
//更新界面操作必须借助多线程来实现
new Thread(new Runnable()
{
@Override
public void run()
{
//当前内存中还留有进程未执
while(currentPCBsNum!=0 && !isStopScheduling)
{
//此算法需要三个队列,分别是UnArrive队列,Waitting队列,和Running队列
LinkedList<PCB> queue1 = PCBsQueues[2].getQueue();//UnArrive队列
LinkedList<PCB> queue2 = PCBsQueues[3].getQueue();//Waitting队列
LinkedList<PCB> queue3 = PCBsQueues[4].getQueue();//Running队列
Collections.sort(queue1, new compareArrive());//对UnArrive队列按照到达时间升序排队
Collections.sort(queue2, new compareHRR());//对Waitting队列按照响应比降序排序
textArea.setText(String.valueOf(nowTime));//用于在时钟对应位置展示此时的nowTime,即当前时间
boolean flag = true;//标志
while((queue1.size()>0)&&(flag)) {//UnArrive队列非空且flag为true
flag=false;//设置flag为false
PCB pcb1 = queue1.element();//获取UnArrive队列第一个进程
if(pcb1.getarriveTime()<=nowTime) {//判断进程是否已经到达
queue1.poll(); //若到达,则将进程从UnArrive队列删除
pcb1.setStatus("Waitting"); //设置进程状态为Waitting
queue2.offer(pcb1); //将进程添加到Waitting队列
flag=true; //flag设为true,表示进程进入过该if选择语句
} //因为UnArrive队列已经按照到达时间排序,所以一旦UnArrive队列队列首个元素都未到达,后边进程不必再判断,无法进入if选择语句,flag无法变为true,while循环结束
}
Collections.sort(queue2, new compareHRR());//对Waitting队列再次按照响应比排序
if(queue2.size()>0) {//如果Waitting队列不为空
if(queue3.size()==0) {//Running队列为空
PCB pcb3 = queue2.element();//获取Waitting队列第一个进程
queue2.poll();//删除该进程
pcb3.setStatus("Running");//设置进程状态为Running
float temp=nowTime-pcb3.getarriveTime();//根据当前时间和到达时间之差计算等待时间
pcb3.setwaitTime(temp);//设置等待时间
queue3.offer(pcb3);//将进程添加到Running队列运行
}
else //Running队列不为空
{
PCB pcb3=queue3.element();//获取Running队列第一个进程
int pid=pcb3.getPid();//获取进程ID
float temp1=nowTime-pcb3.getarriveTime();//当前时间减去到达时间
float temp2=temp1-pcb3.getwaitTime();//再减去等待时间,即为该进程的已运行时间
float temp3=pcb3.getserveTime()-temp2;//进程总服务时间减去已运行时间,获得进程剩余服务时间
pcb3.setSurplusServeTime(temp3);//设置进程的剩余服务时间
if(temp3<=0) {//剩余服务时间小于0,即运行结束
queue3.poll();//删除该进程
pidsUsed[pid] = 0;//设置该进程ID未使用
currentPCBsNum--;//进程数减1
PCB pcb4=queue2.element();//获得Waitting队列第一个进程
queue2.poll();//删除该进程
pcb4.setStatus("Running");//设置运行状态
float temp=nowTime-pcb4.getarriveTime();//计算等待时间
pcb4.setwaitTime(temp);//设置等待时间
queue3.offer(pcb4);//将该进程添加到Running队列队尾
}
}
}
else {//如果Waitting队列为空
if(queue3.size()>0) {//Running队列不为空
PCB pcb3=queue3.element();//获取Running队列第一个进程
int pid=pcb3.getPid();//获取进程ID
float temp1=nowTime-pcb3.getarriveTime();//当前时间减去到达时间
float temp2=temp1-pcb3.getwaitTime();//再减去等待时间,即为该进程的已运行时间
float temp3=pcb3.getserveTime()-temp2;//进程总服务时间减去已运行时间,获得进程剩余服务时间
pcb3.setSurplusServeTime(temp3);//设置进程的剩余服务时间
if(temp3<=0) {//剩余服务时间为小于0,即运行结束
queue3.poll();//删除该进程
pidsUsed[pid] = 0;//设置该进程ID未使用
currentPCBsNum--;//进程数减1
}
}
}
PCBsQueues[2].setQueue(queue1);//将UnArrive队列放回队列组
PCBsQueues[3].setQueue(queue2);//将Waitting队列放回队列组
PCBsQueues[4].setQueue(queue3);//将Running队列放回队列组
showPCBQueues(PCBsQueues);
if(currentPCBsNum==0) {
break;//内存内无进程,跳出while循环
}
try
{
Thread.sleep((int)(1 * 5000));//每次循环sleep一个时间片的时间
}
catch (InterruptedException e)
{
e.printStackTrace();
}
nowTime=nowTime+1;//当前时间加1,表示时钟走过一秒
}
initMemory();//内存初始化
showPCBQueues(PCBsQueues);//展示队列组
//有进程均执行完成,进程调度完
JOptionPane.showMessageDialog(frame, "进程调度完成!");
//frame.dispose();
}
}).start();
}
4、多级反馈队列调度算法
public static void startMFQ()
{
isStopScheduling = false;
//更新界面操作必须借助多线程来实现
new Thread(new Runnable()
{
@Override
public void run()
{
//当前内存中还留有进程未执行
while(currentPCBsNum!=0 && !isStopScheduling)
{
textArea.setText(String.valueOf(nowTime));//用于在时钟对应位置展示此时的nowTime,即当前时间
for(int i = PCBsQueues.length - 1; i >= 0; i--)//因队列组的优先级随下标的增加而增加,故从后往前取队列执行操作
{
LinkedList<PCB> queue = PCBsQueues[i].getQueue();//取对应下标的队列出来
//LinkedList<PCB> Nextqueue = PCBsQueues[i-1].getQueue();//取对应下标的队列出来
if (queue.size() > 0)//如果队列有进程,则执行
{
PCB pcb = queue.element(); //读取该队列首个PCB
pcb.setStatus("Running");//设置为运行状态
showPCBQueues(PCBsQueues);//通过展示函数展示PCB的必要信息
int pid = pcb.getPid();//获得PCB的ID
int priority = pcb.getPriority();//获得PCB的优先级
float SurplusServeTime=pcb.getSurplusServeTime();//获得PCB的剩余服务时间
priority = priority-1;//进程已经开始执行,优先级减一
if(priority==-1)
{ //这里讨论当前执行的队列是不是最后一个队列,也就是优先级为0的队列,如果是那么剩下的未执行的进程会按照时间片轮转算法执行
if(SurplusServeTime<=PCBsQueuesTimeSlice[i]) //若该进程剩余服务时间小于时间片
{
while(SurplusServeTime>0) {//剩余服务时间大于0,则循环。用于在进程剩余服务时间小于时间片时,将进程的剩余服务时间执行完
if(isStopScheduling) {//用于调度结束函数判断
break;
}
try//通过sleep函数模拟进程调度所需要的时间
{
Thread.sleep((int)(1 * 4000));//如果剩余服务时间小于时间片,那么sleep剩余服务时间大小的时间
}
catch (InterruptedException e)
{
e.printStackTrace();
}
SurplusServeTime--;//每循环一次,剩余服务时间减1
pcb.setSurplusServeTime(SurplusServeTime);//设置pcb剩余服务时间
PCBsQueues[i].setQueue(queue);//将队列放置回队列组
showPCBQueues(PCBsQueues);//展示队列组信息,体现进程剩余服务时间在递减的动态变化
nowTime++;//当前时间递增
textArea.setText(String.valueOf(nowTime));//用于在时钟对应位置展示此时的nowTime,即当前时间
}
queue.poll();移除该队列的首个PCB
pidsUsed[pid] = 0;//此数组记录进程是否被创建,创建则为1,未创建则为0,因为此进程执行结束,所以把数组中该ID对应的数值设为0.表示内存中无此ID的进程了
currentPCBsNum--;//内存进程数减1
}
else//若该进程剩余服务时间大于时间片
{
double temp=PCBsQueuesTimeSlice[i];//用中间值表示需运行的时间片
while(temp>0) {//运行时间片,直至为0,跳出while循环
if(isStopScheduling) {//用于调度结束函数判断
break;
}
try
{
Thread.sleep((int)(1 * 4000));//如果剩余服务时间大于时间片,那么sleep剩余时间片大小的时间
}
catch (InterruptedException e)
{
e.printStackTrace();
}
temp--;//需运行时间片减1
SurplusServeTime--;//每循环一次,剩余服务时间减1
pcb.setSurplusServeTime(SurplusServeTime); //设置pcb剩余服务时间
PCBsQueues[i].setQueue(queue);//将队列放置会队列组
showPCBQueues(PCBsQueues);//展示队列组信息,体现进程剩余服务时间在递减的动态变化
nowTime++;//当前时间递增
textArea.setText(String.valueOf(nowTime));//用于在时钟对应位置展示此时的nowTime,即当前时间
}
//SurplusServeTime=(float) (SurplusServeTime-PCBsQueuesTimeSlice[i]);//剩余服务时间减去时间片
queue.poll(); //移除该队列的首个PCB
pcb.setPriority(priority+1);//之前减了1,优先级变成了-1,此时加上1,优先级变为0,表示还是最后一个队列
pcb.setSurplusServeTime(SurplusServeTime);//设置剩余服务时间
pcb.setStatus("Ready");//设置状态为ready
//LinkedList<PCB> Queue = PCBsQueues[i].getQueue();//获得该优先级最低的队列,也就是此队列
queue.offer(pcb);//将未执行完的进程添加到队尾
PCBsQueues[0].setQueue(queue);//将队列放置会队列组
showPCBQueues(PCBsQueues);//展示队列组信息,体现进程剩余服务时间在递减的动态变化
}
}
else//如果此队列不是优先级最小的队列
{
if(SurplusServeTime<=PCBsQueuesTimeSlice[i])//若该进程剩余服务时间小于时间片
{
while(SurplusServeTime>0) {//剩余服务时间大于0,则循环。用于在进程剩余服务时间小于时间片时,将进程的剩余服务时间执行完
if(isStopScheduling) {//用于调度结束函数判断
break;
}
try//通过sleep函数模拟进程调度所需要的时间
{
Thread.sleep((int)(1 * 4000));//如果剩余服务时间小于时间片,那么sleep剩余服务时间大小的时间
}
catch (InterruptedException e)
{
e.printStackTrace();
}
SurplusServeTime--;//每循环一次,剩余服务时间减1
pcb.setSurplusServeTime(SurplusServeTime); //设置pcb的剩余服务时间
PCBsQueues[i].setQueue(queue);//将队列放置会队列组
showPCBQueues(PCBsQueues);//展示队列组信息,体现进程剩余服务时间在递减的动态变化
nowTime++;//当前时间递增
textArea.setText(String.valueOf(nowTime));//用于在时钟对应位置展示此时的nowTime,即当前时间
}
queue.poll(); //移除该队列的首个PCB
pidsUsed[pid] = 0;//此数组记录进程是否被创建,创建则为1,未创建则为0,因为此进程执行结束,所以把数组中该ID对应的数值设为0.表示内存中无此ID的进程了
currentPCBsNum--;//内存进程数减1
}
else//若该进程剩余服务时间大于时间片
{
double temp=PCBsQueuesTimeSlice[i];//用中间值表示需运行的时间片
while(temp>0) {//运行时间片,直至为0,跳出while循环
if(isStopScheduling) {//用于调度结束函数判断
break;
}
try
{
Thread.sleep((int)(1 * 4000));//如果剩余服务时间大于时间片,那么sleep剩余时间片大小的时间
}
catch (InterruptedException e)
{
e.printStackTrace();
}
temp--;//需运行时间片减1
SurplusServeTime--;//每循环一次,剩余服务时间减1
pcb.setSurplusServeTime(SurplusServeTime); //设置pcb的剩余运行时间
PCBsQueues[i].setQueue(queue);//将队列放置回队列组
if(temp!=0) {
showPCBQueues(PCBsQueues);
}
//showPCBQueues(PCBsQueues);
nowTime++;//当前时间加1
textArea.setText(String.valueOf(nowTime));//用于在时钟对应位置展示此时的nowTime,即当前时间
}
//SurplusServeTime=(float) (SurplusServeTime-PCBsQueuesTimeSlice[i]);//剩余服务时间减去时间片
queue.poll();//移除该队列的首个PCB
pcb.setPriority(priority);//设置队列优先级
pcb.setSurplusServeTime(SurplusServeTime);//设置队列的剩余服务时间
pcb.setStatus("Ready");//设置状态为ready
LinkedList<PCB> nextQueue = PCBsQueues[i-1].getQueue();//此处取得优先级低一等级的队列,也就是把未执行完的队列添加到下一级队列的队尾
nextQueue.offer(pcb);//把未执行完的队列添加到下一级队列的队尾
PCBsQueues[i-1].setQueue(nextQueue);//将取出的队列放回队列组
showPCBQueues(PCBsQueues);
}
}
//nowTime++;
textArea.setText(String.valueOf(nowTime));//用于在时钟对应位置展示此时的nowTime,即当前时间
break;//跳出for循环
}
}
}
if(isStopScheduling) {
//nowTime=0;
textArea.setText(String.valueOf("0.0"));//用于在时钟对应位置展示此时的nowTime,即当前时间
}
initMemory();//进程执行结束,初始化内存
showPCBQueues(PCBsQueues);
//所有进程均执行完成,进程调度完
JOptionPane.showMessageDialog(frame, "进程调度完成!");
//frame.dispose();
}
}).start();
}
三、运行界面
1、运行预览
2、主界面
以多级反馈队列算法为例,其他算法大致相同。
四、源代码下载
https://github.com/LZshangan/OSProcessSchduling
支持开源,希望能帮助有需要的人,欢迎下载,欢迎完善。