Java programming language logo

Thread Interruption

A thread can be interrupted by invoking the interrupt method on it, but this method does not directly interrupt it. It depends on the current thread, how to react to an interruption request.

The interrupt method sets the interrupt status of the thread. The thread has to check this status periodically for supporting its own interruption.

If a thread invoking a method that supports interruption, then that method throws an InterruptedException, which is caught by the run method, and after that it can return. The sleep and join methods throw InterruptedException, so they support interruption.

Interruptible Thread

In the next example, the thread wants to count from one to twenty and prints out the numbers. It calls the sleep method for 100 milliseconds before every count, so it needs two seconds for completing the counting.

The thread is started by the main thread. It waits for it one second by the thread.join(1000) call, but after that it interrupts the thread.

The sleep method throws InterruptedException, so it has to be surrounded with a try/catch block. Adding a throws declaration to the run method is not an option because run cannot throw any exception.

The for loop is terminated by the break statement, so the run method finishes the counting.


package com.programcodex.concurrency.thread.interrupt;

public class ThreadInterruptible implements Runnable {

    @Override
    public void run() {
        System.out.println("I'm counting to twenty.");

        for (int i = 1; i < 20; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                System.out.println("\nI'm interrupted :(");
                break;
            }
            System.out.print(i + " ");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new ThreadInterruptible());
        thread.start();
        thread.join(1000);
        thread.interrupt();
    }
}

The output of the above class:

Interruptible Thread

Uninterruptible Thread

The above code can be modified to not support the interruption. It’s unlikely this ever needed, but it can be done easily.

In the below example, only the break statement got removed from the catch block, so the thread catches the InterruptedException, but does not return. It continues the counting.


package com.programcodex.concurrency.thread.interrupt;

public class ThreadUninterruptible implements Runnable {

    @Override
    public void run() {
        System.out.println("I'm counting to twenty.");

        for (int i = 1; i <= 20; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                System.out.println("\nOhh, an InterruptedException. I ignore it.");
                System.out.println("I always finish what I have started.");
            }
            System.out.print(i + " ");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new ThreadUninterruptible());
        thread.start();
        thread.join(1000);
        thread.interrupt();
    }
}

The output of the above class:

Uninterruptible Thread

Interrupt Status Check

Now let’s see what happens, if the thread does not invoke any method that supports interruption.

The next example shows a thread that cannot be interrupted. It generates random numbers until it generates the number 1. Obviously, this code yield nothing useful, but it demonstrates a long running operation, that can take some time.

The main method starts a thread and immediately tries to interrupt it. The thread cannot be interrupted, so it completes its task anyway. As you can see from the output, the thread took more than a second to finish instead of zero millisecond.

The thread.isInterrupted() returns with true if the thread is interrupted.


package com.programcodex.concurrency.thread.interrupt;

import java.util.Random;

public class ThreadUninterruptible2 implements Runnable {

    private Random random = new Random();

    @Override
    public void run() {
        longRunningOperation();
        print("I'm done.");
    }

    private void longRunningOperation() {
        print("Starting a long running operation.");
        long start = System.currentTimeMillis();

        int r = 0;
        while (r != 1) {
            r = random.nextInt(100_000_000);
        }

        long end = System.currentTimeMillis();
        print("It took " + (end - start) + " milliseconds.");
    }

    private static void print(String msg) {
        String threadName = Thread.currentThread().getName();
        System.out.format("%s: %s%n", threadName, msg);
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new ThreadUninterruptible2());
        thread.start();
        print("thread.isInterrupted() is " + thread.isInterrupted());
        thread.interrupt();
        print("thread.isInterrupted() is " + thread.isInterrupted());
        print("I'm done.");
    }
}

The output of the above class:

Interrupt Status Check

To fix the previous problem, we have to introduce the Thread.interrupted() method, which returns with true if the thread has been interrupted. If the thread wants to support interruption, it should check its interrupt status flag periodically by the interrupted static method. In the next example, it is called from the while loop. If the thread is interrupted before it finds the right number, it quits from the loop and finishes its task.

Important: the Thread.interrupted() method also sets the interrupt status flag back to false. So in the while loop the method returns with true, but right after at the end of the run method, it returns with false even though it has been interrupted.

This is not apply to the non-static isInterrupted method, which is called on a thread instance. That does not sets the status.


package com.programcodex.concurrency.thread.interrupt;

import java.util.Random;

public class ThreadIsInterrupted implements Runnable {

    private Random random = new Random();
    private int r;

    @Override
    public void run() {
        longRunningOperation();

        if (r != 1) {
            print("I'm not done just interrupted.");
            print("My interrupt status flag is " + Thread.interrupted());
        }
    }

    private void longRunningOperation() {
        print("Starting a long running operation.");
        long start = System.currentTimeMillis();

        while (r != 1 && !Thread.interrupted()) {
            r = random.nextInt(100_000_000);
        }

        long end = System.currentTimeMillis();
        print("It took " + (end - start) + " milliseconds.");
    }

    private static void print(String msg) {
        String threadName = Thread.currentThread().getName();
        System.out.format("%s: %s%n", threadName, msg);
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new ThreadIsInterrupted());
        thread.start();

        print("I wait 1 second for the thread.");
        thread.join(1000);

        print("Enough. I interrupt the thread.");
        thread.interrupt();
        print("I'm done.");
    }
}

The output of the above class:

Is Thread Interrupted

If the thread finishes before the interruption, the output can be:

Thread Interrupt