Snap to it and then how to deal with it?
Many Java™ language methods, such as Thread.sleep()
and Object.wait()
, can be thrown InterruptedException
. You cannot ignore this exception because it is a check exception (checked exception). But what should be done about it? In Java theory and practice this month, the concurrency expert Brian Goetz will explain Interruptedexception's meaning, why it throws interruptedexception, and what to do when it catches the exception.
You may not be unfamiliar with this scenario: you are writing a test program, and the program needs to be paused for a while, and then called Thread.sleep()
. But the compiler or IDE reported that there was no processing to check InterruptedException
. InterruptedException
What is it, why must we deal with it?
InterruptedException
a common way to deal with this is "eat (swallow)" It--capturing it, and then doing nothing (or recording it, but that's not much better)--just like in Listing 4 later. Unfortunately, this approach ignores the fact that interruptions can occur during this period, and interruptions can cause the application to lose its ability to cancel activities or shutdowns in a timely manner.
Blocking methods
When a method throws InterruptedException
, it not only tells you that it can throw a particular check exception, but also tells you something else. For example, it tells you that it is a blocking (blocking) method, and if you respond properly, it will try to eliminate blocking and return as early as possible.
The blocking method differs from the usual method of running for a longer period of time. The general method's completion depends only on what it wants to do, and whether there are enough compute resources available (CPU cycles and memory). The completion of the blocking method also depends on some external events, such as timer expiry, I/O completion, or the action of another thread (releasing a lock, setting a flag, or putting a task in a work queue). The general approach ends when their work is done, and the blocking methods are more difficult to predict because they depend on external events. Blocking methods can affect responsiveness because it is difficult to predict when they will end.
Blocking methods can be useful because they cannot be terminated because they cannot wait for an event to wait for them to be canceled , which is often useful if a long-running non-blocking method can be canceled. A cancel operation refers to an operation that can be terminated externally before it is completed normally. Thread
Thread.sleep()
Object.wait()
The interrupt mechanism provided and supported is a cancellation mechanism that allows one thread to request that another thread stop what it is doing. When a method throws InterruptedException
, it is telling you that if the thread that executes the method is interrupted, it will try to stop the thing it is doing while returning it early, and by throwing InterruptedException
it back in advance to indicate it. A well-behaved blocking library method should be able to respond to interrupts and throw them so that they can be InterruptedException
used to cancel the activity without affecting the response.
Thread break
Each thread has a Boolean property associated with it that represents the interrupt state of the thread (interrupted status). The interrupt state is initially false, Thread.interrupt()
and one of the following two scenarios occurs when another thread breaks a thread by calling. If that thread is executing a low-level interruptible blocking method, for example Thread.sleep()
, Thread.join()
or Object.wait()
, then it will unblock and throw InterruptedException
. Otherwise, interrupt()
just set the interrupt state of the thread. Code running in the interrupted thread can then poll the interrupt state to see if it is being requested to stop what it is doing. The interrupt state can be Thread.isInterrupted()
read by, and can be Thread.interrupted()
read and purged through a named operation.
Interrupts are a collaborative mechanism. When a thread breaks another thread, the interrupted thread does not have to immediately stop what it is doing. Instead, a break is a polite request to another thread to stop what it is doing when it is willing and convenient. Some methods, for example Thread.sleep()
, take such requests very seriously, but each method does not necessarily respond to interrupts. For interrupt requests, a method that does not block but still takes a long time to execute can poll the interrupt state and return early when it is interrupted. You can ignore interrupt requests at will, but doing so can affect the response.
One of the benefits of interrupted collaboration features is that it provides greater flexibility in constructing a removable activity safely. We seldom want an activity to stop immediately, and if the activity is canceled while an update is in progress, the program data structure may be in an inconsistent state. Interrupts allow a removable activity to clean up work in progress, restore invariants, and notify other activities that it will be canceled before terminating.
Back to top of page
Handling Interruptedexception
If throwing InterruptedException
means that a method is a blocking method, then calling a blocking method means that your method is also a blocking method, and you should have some kind of strategy to handle InterruptedException
. Usually the easiest strategy is to throw it yourself InterruptedException
, as shown in Listing 1 putTask()
and getTask()
the code in the method. Doing so allows the method to respond to interrupts and simply InterruptedException
adds to the throws clause.
Listing 1. Do not capture interruptedexception, propagate it to the caller
public class Taskqueue { private static final int max_tasks = +; Private blockingqueue<task> Queue = new linkedblockingqueue<task> (max_tasks); throws Interruptedexception { queue.put (r); } throws Interruptedexception { return queue.take (); }}
Sometimes you need to do some cleanup before propagating the exception. In this case, you can catch InterruptedException
, perform cleanup, and then throw an exception. Listing 2 illustrates this technique, which is a mechanism for matching players in online game services. matchPlayers()
method waits for two players to arrive and then start a new game. If the method is interrupted when a player has arrived but another player is still not there, then it will put that player back in the queue and re-throw it InterruptedException
so that the player's request for the game is not lost.
Listing 2. Perform task-specific cleanup work before re-throwing interruptedexception
public class Playermatcher { private playersource players; Public Playermatcher (Playersource players) { this.players = players; } throws Interruptedexception { try { Player playerone, playertwo; while (true) { Playerone = Playertwo = null; Wait for the players to arrive and start a new game Playerone = Players.waitforplayer ();//could throw IE Pl Ayertwo = Players.waitforplayer (); Could throw IE startnewgame (Playerone, playertwo); } } catch (Interruptedexception e) { //If We got one player and were interrupted, put that player back If (Playeron E! = null) Players.addfirst (playerone); Then propagate the exception throw e;}} }
Do not eat interrupt
Sometimes throwing is InterruptedException
inappropriate, for example Runnable
, when an interruptible method is called by a defined task. In this case, it cannot be re InterruptedException
-thrown, but you do not want to do nothing. When a blocking method detects an interrupt and throws InterruptedException
it, it clears the interrupt state. If InterruptedException
it is caught but cannot be re-thrown, then the evidence of the interruption should be preserved so that the higher-level code in the call stack can know the interrupt and respond to the interrupt. The task can be done by calling interrupt()
to "re-break" the current thread, as shown in Listing 3. At a minimum, whenever InterruptedException
you snap to it and do not re-throw it, the current thread is re-interrupted before it is returned.
Listing 3. Resume interrupt status after capturing Interruptedexception
public class Taskrunner implements Runnable { private blockingqueue<task> queue; Public Taskrunner (blockingqueue<task> queue) { this.queue = queue; } public void Run () { try { while (true) { Task task = Queue.take (timeunit.seconds); Task.execute (); } } catch (Interruptedexception e) { //Restore the interrupted status thread.currentthread (). interrupt (); } }}
The worst thing to do InterruptedException
when processing is to eat it--to catch it, and then neither to re-throw it or to re-assert the interrupt state of the thread. The most standard way to handle an exception that does not know how to handle it is to catch it and then record it, but this method is still the same as eat interrupt, because the higher-level code in the call stack is still unable to get information about the exception. (It's InterruptedException
not wise to just record, because it's too late to deal with it when people come to read the log.) Listing 4 shows a widely used pattern, which is also a pattern of eat interrupts:
Listing 4. Eat interrupted--don't do this.
Don ' t do the public class Taskrunner implements Runnable { private blockingqueue<task> queue; Public Taskrunner (blockingqueue<task> queue) { this.queue = queue; } public void Run () { try { while (true) { Task task = Queue.take (timeunit.seconds); Task.execute (); } } catch (Interruptedexception swallowed) {/ * DON ' T do this-restore the interrupted STATUS INSTEAD */ }} }
If you cannot re InterruptedException
-throw, you still need to re-interrupt the current thread, regardless of whether you plan to process the interrupt request, because there may be multiple "receivers" for an interrupt request. The standard thread pool ( ThreadPoolExecutor
) worker thread implementation is responsible for interrupts, so interrupting a task running in a thread pool can have a double effect, one is to cancel the task, and the other is to inform the thread pool that the execution threads are shutting down. If the task eat an interrupt request, the worker thread will not be aware of a requested interrupt, delaying the application or service shutdown.
Back to top of page
Implement to cancel a task
The language specification does not provide specific semantics for interrupts, but in larger programs it is difficult to maintain any interrupt semantics except cancellation. Depending on what activity it is, users can request cancellation through a GUI or through a network mechanism, such as JMX or WEB services. Program logic can also request cancellation. For example, if a Web crawler (crawler) detects that a disk is full, it automatically shuts itself down, or a parallel algorithm initiates multiple threads to search different areas of the solution space, and once one of the threads finds a solution, it cancels those threads.
Just because a task can be canceled does not mean that an immediate response to the interrupt request is required. For tasks that execute code in a loop, you typically only need to check for interrupts for each iteration of a loop. Depending on how long the loop executes, it may take some time for any code to notice that the thread has been interrupted (either by calling the Thread.isInterrupted()
method to poll the interrupt state, or by calling a blocking method). If the task needs to improve responsiveness, it can poll the interrupt state more frequently. The blocking method usually polls the interrupt state immediately at the ingress, and if it is set up to improve responsiveness, it is also thrown InterruptedException
.
The only time you can eat interrupts is when you know the line is impersonating to exit. This scenario occurs only if the class that invokes the Interruptible method is Thread
part of the case, rather than the Runnable
General library code, as shown in Listing 5. Listing 5 creates a thread that enumerates the prime numbers until it is interrupted, allowing the thread to exit when it is interrupted. The loop used to search for prime numbers checks for interrupts in two places: one is the head polling method in the while loop isInterrupted()
, and the other is the call blocking method BlockingQueue.put()
.
Listing 5. If you know the line is impersonating to exit, you can eat interrupt
public class Primeproducer extends Thread { private final blockingqueue<biginteger> queue; Primeproducer (blockingqueue<biginteger> queue) { this.queue = queue; } public void Run () { try { BigInteger p = biginteger.one; while (! Thread.CurrentThread (). isinterrupted ()) queue.put (P = p.nextprobableprime ()); } catch ( Interruptedexception consumed) {/ * allow thread to exit * /}} public void Cancel () {Interrupt ()}}
Non-disruptive blocking methods
Not all blocking methods are thrown InterruptedException
. The input and output stream classes block waiting for I/O completion, but they are not thrown and are InterruptedException
not returned prematurely if interrupted. However, for socket I/O, if a thread closes the socket, the blocking I/O operation on that socket ends prematurely and throws one SocketException
. java.nio
the non-blocking I/O class in does not also support interruptible I/O, but can also Selector
cancel blocking operations by closing the channel or wake on request. Similarly, an attempt to acquire an internal lock (into a synchronized
block) cannot be interrupted, but it supports an ReentrantLock
interruptible fetch pattern.
Non-canceled tasks
Some tasks refuse to be interrupted, which makes them non-canceled. However, even non-canceled tasks should attempt to preserve the interrupt state, in case the code at the higher level of the call stack needs to process the interrupt after the non-canceled task ends. Listing 6 shows a method that waits for a blocking queue until an available item appears in the queue, regardless of whether it is interrupted. To make it easier for others, it resumes the interrupt state in a finally block after the end, so as not to deprive the caller of the interrupt request of the right. (It cannot resume the interrupt state at an earlier time because that would result in an infinite loop-the BlockingQueue.take()
interrupt state is immediately polled at the entrance, and if a set of interrupt states is found, it will be thrown InterruptedException
.) )
Listing 6. Non-canceled task to resume the interrupt state before returning
Public Task getnexttask (blockingqueue<task> queue) { Boolean interrupted = false; try { while (true) { try { return Queue.take () } catch (Interruptedexception e) { interrupted = True ; Fall through and retry } } } finally { if (interrupted) thread.currentthread (). interrupt (); }}
Back to top of page
Conclusion
You can use the collaboration interrupt mechanism provided by the Java platform to construct a flexible cancellation policy. Activities can decide for themselves whether they are either canceled or non-canceled, and how to respond to interrupts, which can be deferred if immediate return can compromise application integrity. Even if you want to completely ignore interrupts in your code, you should make sure that you resume the interrupt state if you catch it InterruptedException
without re-throwing it, lest the code calling it cannot know that the interrupt occurred.
Translated from: http://www.ibm.com/developerworks/cn/java/j-jtp05236.html
The original author was Brian Goetz. Please respect the copyright of the original author
Java Theory and Practice: dealing with Interruptedexception