Interruption and cancellation

Multithreading · lesson 24 of 38 · 4 min read

Stop work in flight the only way Java allows: set a flag, and write tasks that watch for it.

Open this lesson in the learning hub

Key points

  • interrupt() sets a flag on the thread. It stops nothing by itself. The task has to cooperate.
  • A blocking call like sleep or take turns that flag into InterruptedException and clears it.
  • A busy loop has to test Thread.currentThread().isInterrupted() itself, or it will never stop.
  • Never swallow InterruptedException. Either end the task, or call interrupt() again to restore the flag.
  • future.cancel(true) interrupts the running task. cancel(false) only stops a task that has not started.
  • shutdownNow() interrupts everything running and returns the tasks that never got to start.

Example

import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) throws Exception {
        // 1. a busy loop has to check the flag itself
        Thread poller = new Thread(() -> {
            long n = 0;
            while (!Thread.currentThread().isInterrupted()) n++;
            System.out.println("poller  : noticed the flag and stopped");
        });
        poller.start();
        Thread.sleep(50);
        poller.interrupt();
        poller.join();

        // 2. a blocking call turns the flag into an exception and clears it
        Thread sleeper = new Thread(() -> {
            try { Thread.sleep(5000); }
            catch (InterruptedException e) {
                Thread.currentThread().interrupt();          // restore it, then leave
                System.out.println("sleeper : caught it, flag restored = " + Thread.currentThread().isInterrupted());
            }
        });
        sleeper.start();
        Thread.sleep(50);
        sleeper.interrupt();
        sleeper.join();

        // 3. cancel(true) interrupts the thread running the task
        ExecutorService pool = Executors.newSingleThreadExecutor();
        Future<String> f = pool.submit(() -> { Thread.sleep(5000); return "never"; });
        Thread.sleep(50);
        System.out.println("cancel  : " + f.cancel(true));
        try { f.get(); } catch (CancellationException e) { System.out.println("get     : CancellationException"); }

        pool.shutdownNow();
        System.out.println("pool    : terminated = " + pool.awaitTermination(2, TimeUnit.SECONDS));
    }
}

Cancellation is a request. Write tasks that listen for it.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Multithreading course, and every lesson in it is listed on the Multithreading contents page.