Objective
A common treatment for interruptedexception is to "Swallow (swallow)" It--capture it, then do nothing (or record it, but it's not much better)--as in Listing 4 later. Unfortunately, this approach ignores the fact that interruptions can occur during this period, and interruptions can cause applications to lose the ability to cancel activities or shutdowns in a timely manner.
Blocking method
When a method throws a interruptedexception, it not only tells you that it can throw a specific 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 attempt to eliminate blocking and return as soon as possible.
Blocking methods are different from normal methods that run for a long time. The completion of a generic method depends only on what it does and whether there are enough computing resources (CPU cycles and memory) available. The blocking method's completion also depends on some external events, such as a timer expiration, I/O completion, or another thread's action (releasing a lock, setting a flag, or putting a task in a work queue). General methods end when their work is done, and 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 not be terminated because they cannot wait for an event, so it is useful to cancel the blocking method (which is often useful if the long-running non-blocking method is canceled). A cancel operation is an operation that can be terminated from the outside before it is normally completed. The interrupt mechanism provided by thread and supported by Thread.Sleep () and object.wait () is a cancellation mechanism that allows one thread to request another thread to stop what it is doing. When a method throws a interruptedexception, it tells you that if the thread that executes the method is interrupted, it will try to stop the thing it is doing and return in advance, and by throwing interruptedexception indicates that it returns early. A well behaved blocking library method should be able to respond to interrupts and throw interruptedexception so that it can be used to cancel the activity without affecting the response.
Thread Interrupt
Each thread has a Boolean attribute associated with it that represents the interrupt state of the thread (interrupted status). The break state is initially false, and one of the following two cases occurs when another thread interrupts a thread by calling Thread.Interrupt (). If the thread is executing a low-level interruptible blocking method, such as Thread.Sleep (), Thread.Join (), or object.wait (), it will unblock and throw interruptedexception. Otherwise, interrupt () simply sets the interrupt state of the thread. The code that runs in the interrupted thread can then poll the interrupt state to see if it has been requested to stop what is being done. The interrupt state can be read by thread.isinterrupted () and can be read and purged by an operation named Thread.interrupted ().
Interrupts are a collaborative mechanism. When one thread interrupts another, the interrupted thread does not have to stop what is being done immediately. Instead, interrupts are politely asking another thread to stop what it is doing when it is willing and convenient. Some methods, such as Thread.Sleep (), take such requests seriously, but each method does not necessarily respond to interrupts. For interrupt requests, methods that do not block but still take a long time to execute can poll the interrupt state and return early when interrupted. You can ignore interrupt requests at will, but doing so affects the response.
One of the benefits of disruptive collaboration features is that it provides greater flexibility to securely construct a removable activity. We rarely want an activity to stop immediately, and if the activity is canceled while the update is in progress, the program data structure may be in an inconsistent state. Interrupts allow an activity to be canceled to clean up work in progress, restore invariants, and notify other activities that it will be canceled before terminating.
Handling Interruptedexception
If throwing interruptedexception means that one 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 the interruptedexception. Often the easiest strategy is to throw interruptedexception yourself, as shown in the code in the Puttask () and Gettask () methods in Listing 1. Doing so allows the method to respond to interrupts and simply adds interruptedexception to the throws clause.
Listing 1. Does not capture interruptedexception and propagates it to the caller
public class Taskqueue {
private static final int max_tasks = 1000;
Private blockingqueue<task> Queue
= new linkedblockingqueue<task> (max_tasks);
public void Puttask (Task R) throws Interruptedexception {
queue.put (r);
}
Public Task Gettask () throws Interruptedexception {return
queue.take ();
}
}
Sometimes you need to do some cleanup before you propagate an 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 an online gaming service. The Matchplayers () method waits for two players to arrive, and then starts a new game. If the method is interrupted when a player has arrived, but the other player has not yet arrived, it will put the player back in the queue and then throw the interruptedexception again so that the player's request for the game will not be lost.
Listing 2. Perform task-specific cleanup before interruptedexception is thrown again
public class Playermatcher {
private playersource players;
Public Playermatcher (Playersource players) {
this.players = players;
}
public void Matchplayers () throws Interruptedexception {
try {
Player playerone, playertwo;
while (true) {
Playerone = Playertwo = null;
Wait for two 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 then player back
If (Playeron e!= null)
Players.addfirst (playerone);
Then propagate the exception
throw e;
}
}
Don't swallow the interruption.
Sometimes throwing interruptedexception is not appropriate, for example, when a task defined by Runnable invokes an interruptible method. In this case, you can't throw interruptedexception again, but you don't want to do nothing. When a blocking method detects an interrupt and throws a interruptedexception, it clears the interrupt state. If you catch a interruptedexception but cannot throw it back, you should keep the evidence of the interruption 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 "break" the current thread, as shown in Listing 3. At the very least, each time the interruptedexception is captured and not thrown back, the current thread is interrupted before it is returned.
Listing 3. Recover break 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 when dealing with interruptedexception is to swallow it-catch it, and neither throw it back nor assert the interrupt state of the thread. The most standard way to handle an exception that doesn't know how to handle it is to capture it and then record it, but this method is still the same as breaking a swallow, because the higher-level code in the call stack is still unable to get information about the exception. (It's not wise to just record interruptedexception, because it's too late to wait until someone reads the log and then it's time to take care of it.) Listing 4 shows a widely used pattern, which is also a pattern of the disruption of the swallow:
Listing 4. The interruption of a swallow--don't do that.
Don ' t do this 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 Interruptedexception cannot be thrown again, whether or not you plan to process the interrupt request, the current thread will still need to be interrupted because one interrupt request may have multiple "recipients." 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 notify the thread pool is shutting down. If the task swallows up the interrupt request, the worker thread will not know that there is a requested interrupt, thereby delaying the shutdown of the application or service.
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, a user 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, a Web crawler (crawler) automatically shuts itself down if it detects that the disk is full, otherwise a parallel algorithm launches multiple threads to search for different areas of the solution space, and once one of the threads finds a solution, it cancels those threads.
Just because a task is canceled does not mean that the interrupt request needs to be responded to immediately. For a task that executes code in a loop, it is usually necessary to check for interrupts for Each loop iteration. 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 requires increased responsiveness, it can poll the interrupt status more frequently. Blocking methods usually poll the interrupt state immediately at the portal, and if it is set up to improve responsiveness, it throws interruptedexception.
The only time you can swallow a break is when you know the line one thread to exit. This scenario occurs only if the class that calls the Interruptible method is part of Thread, not Runnable or generic library code, as shown in Listing 5. Listing 5 creates a thread that enumerates 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 interruptions in two places: one is the head polling isinterrupted () method in the while loop, and the other is invoking the blocking method Blockingqueue.put ().
Listing 5. If you know that the line one thread to quit, you can swallow the interruption
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 ());
Interruptedexception consumed} {/
* Allow thread to exit
/}} public
void Cancel () {interrupt ();}
}
Non-disruptive blocking methods
Not all blocking methods throw interruptedexception. Input and output stream classes block waiting I/O completion, but they do not throw interruptedexception and are not returned in advance if they are interrupted. However, for socket I/O, if a thread closes the socket, the blocking I/O operation on that socket ends prematurely and throws a socketexception. Non-blocking I/O classes in Java.nio also do not support interruptible I/O, but can also cancel the blocking operation by closing the channel or by requesting a wake-up call on the Selector. Similarly, an attempt to acquire an internal lock (into a synchronized block) cannot be interrupted, but Reentrantlock supports interruptible access patterns.
Tasks that cannot be canceled
Some of the tasks refused to be interrupted, which made them irrevocable. However, even a task that is not canceled should try to preserve the state of the interrupt, in case the more high-level code on the call stack needs to process the interrupt after the irrevocable 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 or not. For the convenience of others, it restores the interrupt state in a finally block after it has ended, lest it deprive the caller of the interrupt request of the right. (It cannot restore the interrupt state at an earlier time, because that will cause the infinite loop--blockingqueue.take () to poll the interrupt state immediately at the entrance, and if the set of break states is found, the interruptedexception will be thrown.) )
Listing 6. Non-cancel task to restore interrupted 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 () ;
}
}
Summarize
You can construct a flexible cancellation strategy using the collaboration interrupt mechanism provided by the Java platform. Activities can decide for themselves whether they can be canceled or not, and how to respond to interrupts, which can also be deferred if immediate return endangers application integrity. Even if you want to completely ignore interrupts in your code, you should also ensure that the interrupt state is recovered when you capture the interruptedexception but do not throw it back, so that the code that calls it does not know that the interrupt occurred. The above is the Java processing interruptedexception exception of the theory and practice of the whole content, I hope this article is helpful to everyone, if there are questions to welcome comments to discuss.