Thread Scheduler in Java

Naveen AnamaneniUpdated · 4 min read

The thread scheduler is the part of the system that decides which thread runs on a CPU core, and for how long. In modern Java, platform threads are ordinary operating-system threads, so the scheduling is done by the operating system, not by the JVM. Because of this, the order in which threads run is not guaranteed and can change from one run to the next. In this lesson, you will learn how scheduling works, what you can and can't control, and why correct programs never depend on timing.

How Scheduling Works

  • Time slicing: each runnable thread gets a short slice of CPU time, then another thread gets a turn.
  • Preemption: the scheduler can pause a running thread at almost any moment to run another.
  • Multiple cores: with several cores, several threads truly run at the same time.
  • Waiting threads are skipped: threads that are sleeping, waiting or blocked aren't given CPU time.

What You Can and Can't Control

You canYou can't
Decide when a thread starts (start())Decide the exact order threads run in
Make a thread wait (sleep, join, wait)Guarantee how long a time slice lasts
Hint at importance (setPriority)Rely on priorities being honored
Coordinate threads (locks, join, queues)Predict output order without coordination

Example: Unpredictable Order

Let's see an example where three threads print with no coordination. Run it several times; the order may differ, so the output shown is one sample.

NoOrder.java▶ Try it
public class NoOrder {
    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[3];
        String[] names = {"Navika", "Srihitha", "Advitha"};
        for (int i = 0; i < 3; i++) {
            String name = names[i];
            threads[i] = new Thread(() -> {
                for (int k = 1; k <= 2; k++) {
                    System.out.println(name + " " + k);
                }
            });
        }
        for (Thread t : threads) {
            t.start();
        }
        for (Thread t : threads) {
            t.join();
        }
    }
}
Output
Srihitha 1
Srihitha 2
Navika 1
Advitha 1
Navika 2
Advitha 2

Explanation: The threads were started in the order Navika, Srihitha, Advitha, but in this run Srihitha went first, and the scheduler switched between Navika and Advitha mid-loop. Six runs on the same machine gave five different orders. Each thread's own lines stay in order (1 before 2), but lines from different threads can mix in any way.

Testing Threaded Code

Common Mistakes

Using Thread.sleep to "fix" ordering. It only makes a bug rarer; use join, locks or queues.

Assuming higher priority threads always run first. The operating system may ignore priorities.

Expecting the same output on every run. Thread interleaving changes between runs.

Practice

  1. Easy: Run NoOrder five times and write down how many different orders you see.
  2. Harder: Change NoOrder so the output is always Navika's lines, then Srihitha's, then Advitha's, without using sleep.

Quick check: Thread scheduler

4 questions
1Who schedules Java platform threads today?
2Is the order in which started threads run guaranteed?
3What is preemption?
4What should you use to make thread results correct?

Key Takeaways

Was this tutorial helpful?

Lesson 382 of 482