In a Java application, a thread may keep waiting for a long time after executing
Thread.join() or by
take() methods of a BlockingQueue. We also refer such a thread as a blocked thread since it remains blocked until some operation is performed. Sometimes a thread can also be blocked for a certain time by
Thread.sleep(). When a thread is blocked for a long time you may need to take the thread out of the WAITING or TIMED_WAITING state. While writing a Java application, we need to take care that a thread does not remain blocked for too long. The corrective action that needs to be performed in such circumstances depends on the type of task the thread is executing. If the task is cancellable, it is simply aborted and if it is not cancellable then a logic needs to be implemented to enable its execution.
A blocked thread can be interrupted by calling the
interrupt() method of
Thread class. This interrupt is a pure Java mechanism and is neither CPU nor operating system level interrupt. The
interrupt() method does not interrupt a running thread i.e. thread which is in RUNNABLE state. It sets an internal boolean flag called as interrupt status and the thread leaves the WAITING or TIMED_WAITING state. It only interrupts a blocked thread by throwing
InterruptedException. When this exception is thrown, the interrupt status flag is cleared. Whether a thread is interrupted can be checked by the
isInterrupted() method of Thread class. Another method,
Thread.interrupted() returns the interrupt status and also clears it.
A thread which is blocked to acquire an intrinsic lock (BLOCKED state) cannot be interrupted. Similarly, when a thread acquires intrinsic lock, it cannot be interrupted. These are the limitations of intrinsic lock. The thread waiting to obtain a lock can only be interrupted when the lock is obtained by calling the
lockInterruptibly() method of
ReentrantLock. This method also allows the thread which has obtained the lock, to release it when it is interrupted by some other thread. A thread which is blocked to obtain lock by calling the timed
tryLock() method, can also be interrupted.
InterruptedException is a checked exception and it is usually thrown by all blocking methods, so that it can be handled and the corrective action to be performed can be defined. Many programmers usually handle this exception with an empty catch block. Also, a few log this exception. Unless the corrective action i.e. action to be performed when a blocked thread is interrupted is performed, this exception should be propogated to higher level. Simply logging this exception in the log files without performing any corrective action serves no purpose.
A thread which is blocked for performing I/O can be interrupted when Java NIO API is used for peforming I/O. Any channel implementing
InterruptibleChannel is asynchronously closeable and interruptible. When a thread is blocked while performing I/O on
InterruptibleChannel implementation class, the other thread can close the channel by calling its
close() method. This method throws
AsynchronousCloseException. When the other thread invokes the
interrupt() method on the blocked thread, the blocked thread’s interrupt status is set and
ClosedByInterruptException is thrown. When a blocking I/O operation is performed on a channel whose interrupt status is set, the channel is closed and the calling thread receives
ExecutorService interface of Concurrency API introduced in Java 5 provides multiple
submit() methods for asynchronous execution of submitted
Callable tasks. These methods return the result of type
Future which represents the result of computation. The
Future interface provides a method
cancel(boolean mayInterruptIfRunning) to interrupt the executing task by passing boolean value
true to this method. The implementation of this method internally calls
interrupt(). If the task is cancelled, this method returns true. The
cancel() method can also be used to cancel the task which has not started execution.