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.
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:
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:
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:
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:
If the thread finishes before the interruption, the output can be: