SJF Scheduling — New Short Jobs Starve Long Builds
Short build jobs finished fast, but a long integration test waited 4+ hours — uncover the starvation trap in SJF and how aging prevents this problem.
- SJF selects the shortest burst process when CPU becomes free
- Non-preemptive: runs to completion once started
- Preemptive (SRTF): preempts if new process has shorter remaining time
- SJF minimizes average waiting time among non-preemptive algorithms
- Not usable in practice because burst times are unknown
- Starvation risk: long processes may never run if short ones keep arriving
SJF is like a smart cashier who, when finishing a customer, always picks the next customer with the fewest items. This minimises the total time everyone spends waiting. Preemptive SJF (SRTF) is even smarter — if a new short customer arrives while serving a longer one, the cashier switches immediately.
SJF is provably optimal for average waiting time among all non-preemptive scheduling algorithms — and SRTF is optimal among all algorithms including preemptive ones. This optimality is not a heuristic or approximation; it follows directly from an exchange argument. If any solution does not follow SJF order, you can swap adjacent jobs to improve average waiting time.
The practical problem: burst times are not known in advance. Linux's CFS (Completely Fair Scheduler) approximates SJF by tracking vruntime — the virtual runtime each process has accumulated — and always scheduling the process with the smallest vruntime. It is SJF-like without requiring burst time prediction, at the cost of true optimality.
Non-Preemptive SJF
When the CPU becomes free, pick the arrived process with the shortest burst time. Once a process starts, it runs to completion. This is provably optimal among non-preemptive algorithms.
Common misconception: 'Shortest' means smallest expected burst, not actual burst. In practice, we use predicted burst times. The algorithm is also called Shortest Process Next (SPN).
Preemptive SJF — SRTF
Shortest Remaining Time First preempts the running process when a new process arrives with shorter remaining time. It is SJF applied continuously — at every arrival, the scheduler re-evaluates and picks the process with smallest remaining burst.
SRTF achieves the absolute minimum average waiting time among all scheduling algorithms, but at a cost: frequent preemptions can increase context switch overhead, and tracking remaining times adds complexity.
Why SJF is Optimal
SJF minimises average waiting time among all non-preemptive algorithms. Proof by exchange argument: if a longer job runs before a shorter one, swapping them reduces total waiting time. SRTF minimises average waiting time among ALL scheduling algorithms (preemptive and non-preemptive).
The exchange argument is simple: consider two adjacent jobs in a schedule. If a longer job precedes a shorter one, you can swap them and reduce the waiting time of the shorter job by the full length of the longer job, while the longer job waits only the short job's burst. The reduction is always positive.
Starvation and Aging
Starvation occurs when a long process never gets CPU because shorter processes keep arriving. Aging is the standard solution: increase the priority of a process the longer it waits. Priority can be based on waiting time (e.g., priority = base_priority + waiting_time / quantum). Once priority surpasses current running process, the scheduler may preempt.
Aging transforms SJF into a priority-based scheduler with time-dependent boosting. It guarantees every process eventually makes progress, at the cost of slightly increased average waiting time for short processes.
Burst Time Prediction
Real schedulers don't know burst times in advance. Prediction via exponential averaging: τ_{n+1} = α × t_n + (1-α) × τ_n where t_n is actual burst time, τ_n is predicted, α controls responsiveness (typically 0.5).
α close to 1 makes the predictor react quickly to changes but noisy. α close to 0 produces stable predictions but slow to adapt. In Linux's CFS, vruntime replaces burst prediction entirely – the scheduler uses actual CPU usage history instead of predicting future bursts.
Starvation Caused by Burst Time Underestimation in Batch Scheduler
- Starvation is a real production risk with pure SJF – always add aging or use CFS-style fairness.
- Monitor waiting time per process; alert if any process waits more than 10x its expected burst.
- In batch systems, consider using priority+aging instead of pure SJF for long-running jobs.
Key takeaways
Common mistakes to avoid
3 patternsAssuming burst times are known in advance
Using non-preemptive SJF in interactive systems
Ignoring starvation until it causes SLA breaches
Interview Questions on This Topic
Prove that SJF minimises average waiting time among non-preemptive algorithms.
Frequently Asked Questions
That's Scheduling. Mark it forged?
3 min read · try the examples if you haven't