Writing multithreaded programs in Java, with its built-in support forthreads, is fairly straightforward. However, multithreading presents awhole set of new challenges to the programmer that, if not correctlyaddressed, can lead to unexpected behavior and subtle, hard-to-finderrors. In this article, we address one of those challenges: how tointerrupt a running thread.
BackgroundInterruptinga thread means stopping what it is doing before it has completed itstask, effectively aborting its current operation. Whether the threaddies, waits for new tasks, or goes on to the next step depends on theapplication.
Although it may seem simple at first, you must takesome precautions in order to achieve the desired result. There are somecaveats you must be aware of as well.
First of all, forget the
Thread.stop method. Although it indeed stops a running thread, the method is unsafe and was
deprecated, which means it may not be available in future versions of the Java.
Another method that can be confusing for the unadvised is
Thread.interrupt. Despite what its name may imply, the method does not interrupt a running thread (more on this later), as
Listing A demonstrates. It creates a thread and tries to stop it using
Thread.interrupt. The calls to
Thread.sleep() give plenty of time for the thread initialization and termination. The thread itself does not do anything useful.
If you run the code in Listing A, you should see something like this on your console:
Starting thread...Thread is running...Thread is running...Thread is running...Interrupting thread...Thread is running...Thread is running...Thread is running...Stopping application...Even after
Thread.interrupt() is called, the thread continues to run for a while.
Really interrupting a threadThebest, recommended way to interrupt a thread is to use a shared variableto signal that it must stop what it is doing. The thread must check thevariable periodically, especially during lengthy operations, andterminate its task in an orderly manner.
Listing B demonstrates this technique.
Running the code in Listing B will generate output like this (notice how the thread exits in an orderly fashion):
Starting thread...Thread is running...Thread is running...Thread is running...Asking thread to stop...Thread exiting under request...Stopping application...Althoughthis method requires some coding, it is not difficult to implement andgive the thread the opportunity to do any cleanup needed, which is anabsolute requirement for any multithreaded application. Just be sure todeclare the shared variable as
volatile or enclose any access to it into
synchronized blocks/methods.
Sofar, so good! But what happens if the thread is blocked waiting forsome event? Of course, if the thread is blocked, it can't check theshared variable and can't stop. There are plenty of situations when thatmay occur, such as calling
Object.wait(),
ServerSocket.accept(), and
DatagramSocket.receive(), to name a few.
Theyall can block the thread forever. Even if a timeout is employed, it maynot be feasible or desirable to wait until the timeout expires, so amechanism to prematurely exit the blocked state must be used.
Unfortunatelythere is no such mechanism that works for all cases, but the particulartechnique to use depends on each situation. In the following sections,I'll give solutions for the most common cases.
Interrupting a thread with Thread.interrupt()As demonstrated in Listing A, the method
Thread.interrupt()does not interrupt a running thread. What the method actually does isto throw an interrupt if the thread is blocked, so that it exits theblocked state. More precisely, if the thread is blocked at one of themethods
Object.wait,
Thread.join, or
Thread.sleep, it receives an
InterruptedException, thus terminating the blocking method prematurely.
So,if a thread blocks in one of the aforementioned methods, the correctway to stop it is to set the shared variable and then call the
interrupt() method on it (notice that it is important to set the variable first). If the thread is not blocked, calling
interrupt()will not hurt; otherwise, the thread will get an exception (the threadmust be prepared to handle this condition) and escape the blocked state.In either case, eventually the thread will test the shared variable andstop.
Listing C is a simple example that demonstrates this technique.
As soon as
Thread.interrupt()is called in Listing C, the thread gets an exception so that it escapesthe blocked state and determines that it should stop. Running this codeproduces output like this:
Starting thread...Thread running...Thread running...Thread running...Asking thread to stop...Thread interrupted...Thread exiting under request...Stopping application...Interrupting an I/O operationButwhat happens if the thread is blocked on an I/O operation? I/O canblock a thread for a considerable amount of time, particularly ifnetwork communication is involved. For example, a server may be waitingfor a request, or a network application may be waiting for an answerfrom a remote host.
If you're using channels, available with the new I/O API introduced in Java 1.4, the blocked thread will get a
ClosedByInterruptException exception. If that is the case, the logic is the same as that used in the third example—only the exception is different.
Butyou might be using the traditional I/O available since Java 1.0, sincethe new I/O is so recent and requires more work. In this case,
Thread.interrupt() doesn't help, since the thread will not exit the blocked state.
Listing D demonstrates that behavior. Although the
interrupt() method is called, the thread does not exit the blocked state.
Fortunately, the Java Platform provides a solution for that case by calling the
close()method of the socket the thread is blocked in. In this case, if thethread is blocked in an I/O operation, the thread will get a
SocketException exception, much like the
interrupt() method causes an
InterruptedException to be thrown.
The only caveat is that a reference to the socket must be available so that its
close() method can be called. That means the socket object must also be shared.
Listing E demonstrates this case. The logic is the same as in the examples presented so far.
And here's the sample output you can expect from running Listing E:
Starting thread...Waiting for connection...Asking thread to stop...accept() failed or interrupted...Thread exiting under request...Stopping application...Multithreadingis a powerful tool, but it presents its own set of challenges. One ofthese is how to interrupt a running thread. If properly implemented,these techniques make interrupting a thread no more difficult than usingthe built-in operations already provided by the Java Platform.