In a Java application, a thread may keep waiting for a long time after executing wait()
or Thread.join()
or by put()
or 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.
The 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 ClosedByInterruptException
.
The ExecutorService
interface of Concurrency API introduced in Java 5 provides multiple submit()
methods for asynchronous execution of submitted Runnable
or 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.