带时间片的抢占式SJF算法Java程序:输出不符预期求助
问题描述
需要实现**带时间片的抢占式最短作业优先(Pre-emptive SJF With TimeQuantum)**进程调度算法,核心规则如下:
- 给定进程名、到达时间、Burst Time数组及时间片变量;
- 仅允许对已到达的进程执行Burst Time递减操作;
- 每次选择已到达且Burst Time最短的进程:
- 若只有一个最短进程,将其Burst Time减1;
- 若多个已到达进程Burst Time相等,为这些进程各减去时间片时长;
- 重复操作直到所有进程Burst Time为0,每次执行时打印进程名及执行时长。
样例参考
- 样例输入:
("P1", 4, 5),("P2", 1, 6),("P3", 1, 6),("P4", 2, 4),("P5", 3, 3) - 预期输出:
P2 execute 2 unit, P3 execute 2 unit, P5 execute 1 unit, P5 execute 1 unit, P5 execute 1 unit, P2 execute 2 unit, P3 execute 2 unit, P4 execute 2 unit, P2 execute 2 unit, P3 execute 2 unit, P4 execute 2 unit, P1 execute 1 unit, P1 execute 1 unit, P1 execute 1 unit, P1 execute 1 unit, P1 execute 1 unit.
现有Java代码无法输出预期结果,需排查逻辑问题并修正。
原代码核心问题
- 数据关联破坏:直接对
arrivalTime数组排序,导致进程名、到达时间、Burst Time的对应关系完全混乱; - 调度逻辑错误:使用普通队列无法实现“选择已到达且Burst Time最短”的核心逻辑,仅从队列取首个进程,未做最短作业筛选;
- 多进程场景未处理:未判断多个已到达进程Burst Time相同的情况,无法按规则分配时间片;
- 时间与Burst Time更新错误:时间推进和Burst Time修改逻辑不符合“每次减1或时间片”的要求,且未处理无已到达进程时的时间递增;
- 进程未重新调度:执行完时间片的进程未重新加入候选队列,导致后续无法继续调度。
修正后的代码
import java.util.*; class Process { String name; int arrivalTime; int burstTime; int remainingTime; public Process(String name, int arrivalTime, int burstTime) { this.name = name; this.arrivalTime = arrivalTime; this.burstTime = burstTime; this.remainingTime = burstTime; } } public class PreemptiveSJFWithTimeQuantum { public static void main(String[] args) { // 样例输入(可替换为Scanner输入,此处为测试方便直接初始化) List<Process> processes = new ArrayList<>(); processes.add(new Process("P1", 4, 5)); processes.add(new Process("P2", 1, 6)); processes.add(new Process("P3", 1, 6)); processes.add(new Process("P4", 2, 4)); processes.add(new Process("P5", 3, 3)); int timeQuantum = 2; // 对应样例的时间片 int currentTime = 0; List<String> outputRecords = new ArrayList<>(); // 循环直到所有进程完成 while (processes.stream().anyMatch(p -> p.remainingTime > 0)) { // 筛选当前已到达且未完成的进程 List<Process> arrivedProcesses = processes.stream() .filter(p -> p.arrivalTime <= currentTime && p.remainingTime > 0) .toList(); // 无已到达进程时,时间递增 if (arrivedProcesses.isEmpty()) { currentTime++; continue; } // 找到已到达进程中的最小剩余Burst Time int minRemaining = arrivedProcesses.stream() .mapToInt(Process::getRemainingTime) .min() .orElse(Integer.MAX_VALUE); // 筛选出所有剩余时间等于最小值的进程 List<Process> shortestProcesses = arrivedProcesses.stream() .filter(p -> p.remainingTime == minRemaining) .toList(); if (shortestProcesses.size() == 1) { // 单个最短进程:执行1单位时间 Process target = shortestProcesses.get(0); target.remainingTime--; currentTime++; outputRecords.add(target.name + " execute 1 unit"); } else { // 多个最短进程:每个执行时间片时长(不超过剩余时间) for (Process target : shortestProcesses) { int executeDuration = Math.min(timeQuantum, target.remainingTime); target.remainingTime -= executeDuration; currentTime += executeDuration; outputRecords.add(target.name + " execute " + executeDuration + " unit"); } } } // 按预期格式输出结果 System.out.println(String.join(", ", outputRecords) + "."); } }
关键修正说明
- 封装进程实体:用
Process类统一管理进程的所有属性,避免数组排序导致的数据错位; - 精准筛选已到达进程:每次循环先过滤出当前时间点已到达且未完成的进程,符合规则要求;
- 实现最短作业选择:先确定已到达进程的最小剩余Burst Time,再筛选出所有符合该值的进程,满足核心调度逻辑;
- 分场景处理执行逻辑:
- 单个最短进程:每次执行1单位时间,对应规则中Burst Time减1的要求;
- 多个最短进程:每个进程执行时间片时长(不超过剩余时间),符合规则中多进程的处理方式;
- 正确推进时间:无已到达进程时递增时间,有进程执行时根据执行时长更新时间;
- 结果统一输出:用列表收集所有执行记录,最后按预期格式拼接输出。
内容的提问来源于stack exchange,提问作者Forlan Beckham
相关产品推荐
相关产品推荐

