Interrupt Handling
The purpose of interrupts is to allow threads to inform each other when the task they are running might need attention. For example, a thread might be hoarding crucial resources or might have become unresponsive. Whatever corrective action is required is then at the discretion of the thread that is interrupted. Simply catching and ignoring an InterruptedException is not recommended.
The following selected methods from the Thread class can be used for handling interrupts in threads.
void interrupt()
Interrupts the thread on which it is invoked.
If the thread is in a non-runnable state, either blocked or waiting, the interrupt status of the thread is cleared and the thread will receive an InterruptedException when it gets to run.
For a thread that is in the RUNNABLE state, the interrupt status of the thread will be set.
boolean isInterrupted()
Checks whether this thread has been interrupted. The interrupt status of the thread is not affected.
static boolean interrupted()
Checks whether the current thread has been interrupted. The interrupt status of the thread is cleared.
A thread can be interrupted by invoking the method interrupt(). A thread can also invoke this method on itself. How the interrupt manifests in the interrupted thread depends on the state the thread is in when the interrupt() method is invoked. Example 22.5 illustrates the two main scenarios that show how a thread can discover if it has been interrupted—and which a thread should be prepared to handle.
In Example 22.5, the main() method creates and starts a thread at (1) that executes the task defined at (3). The main thread uses an infinite loop at (2) in which it tries to send an interrupt to the worker thread by calling the interrupt() method. Sending an interrupt is dependent on the condition in the if statement being a random even number. If it cannot send an interrupt, the main thread sleeps for awhile before continuing to execute the infinite loop. The main thread exits the infinite loop (and terminates) when it has sent an interrupt to the worker thread.
The task executed by the worker thread is defined by the lambda expression at (3). The task executes an infinite while loop at (4) that illustrates how a thread can discover it has received an interrupt:
- An if statement at (5), which is used to determine if the thread has been interrupted. This corresponds to the first scenario in the output.
If any interrupt is sent to the current thread by calling its interrupt() method while it is running, the interrupt status of the thread will be set. Calling the isInterrupted() method on the current thread in the if statement will then return true.
- A try-catch block at (6) in which the thread sleeps, and catches any Interrupted-Exception that is thrown in response to receiving an interrupt while it was asleep. This corresponds to the second scenario in the output.
If the interrupt() method was called on the thread while it was sleeping, it will result in the interrupt status being cleared and an InterruptedException being thrown in the try block when the thread runs again. Appropriate action can be taken to mitigate the interrupt in the catch block at (7) in which this exception is caught.
Example 22.5 Interrupt Handling
public class InterruptHandling {
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(task, “worker”); // (1)
worker.start();
while (true) { // (2)
if ((int)(Math.random()*100) % 2 == 0) {
worker.interrupt();
break;
}
Thread.sleep(2);
}
}
private static Runnable task = () -> { // (3)
Thread ct = Thread.currentThread();
String threadName = ct.getName();
while (true) { // (4)
System.out.println(threadName + ” performing task”);
if (ct.isInterrupted()) { // (5)
System.out.println(threadName + “: interrupted flag is “
+ ct.isInterrupted());
System.out.println(threadName + ” terminating”);
return;
}
try { // (6)
Thread.sleep(2);
} catch (InterruptedException e) { // (7)
System.out.println(threadName + ” caught ” + e);
System.out.println(threadName + “: interrupted flag is “
+ ct.isInterrupted());
System.out.println(threadName + ” terminating”);
return;
}
}
};
}
Probable output from the program—first scenario:
worker performing task
worker: interrupted flag is true
worker terminating
Probable output from the program—second scenario:
worker performing task
worker performing task
worker caught java.lang.InterruptedException: sleep interrupted
worker: interrupted flag is false
worker terminating