Handling Interruptedexception--brian Goetz

Source: Internet
Author: User
Tags finally block thread stop

This article has been transferred from the post of Brian Goetz Master in IBM's Developerworks:

Chinese Address: http://www.ibm.com/developerworks/cn/java/j-jtp05236.html

English Address: http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html

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 . InterruptedExceptionWhat is it, why must we deal with it?

InterruptedExceptiona 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 InterruptedException throw it yourself , 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 classTaskqueue {Private Static Final intMax_tasks = 1000; PrivateBlockingqueue<task>Queue=NewLinkedblockingqueue<task>(Max_tasks);  Public voidPuttask (Task R)throwsinterruptedexception {queue.put (R); }     PublicTask Gettask ()throwsinterruptedexception {returnQueue.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 classPlayermatcher {PrivatePlayersource players;  PublicPlayermatcher (Playersource players) { This. Players =players; }     Public voidMatchplayers ()throwsinterruptedexception {Try{Player playerone, playertwo;  while(true) {Playerone= Playertwo =NULL; //Wait for the players to arrive and start a new gamePlayerone = Players.waitforplayer ();//could throw IEPlayertwo = Players.waitforplayer ();//could throw IEstartnewgame (Playerone, playertwo); }         }         Catch(interruptedexception e) {//If We got one player and were interrupted, put that player back             if(Playerone! =NULL) Players.addfirst (Playerone); //Then propagate the exception             Throwe; }    }}
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 classTaskrunnerImplementsRunnable {PrivateBlockingqueue<task>queue;  PublicTaskrunner (blockingqueue<task>queue) {          This. Queue =queue; }     Public voidrun () {Try {              while(true) {Task Task= Queue.take (10, Timeunit.seconds);             Task.execute (); }         }         Catch(interruptedexception e) {//Restore the interrupted statusThread.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 this Public classTaskrunnerImplementsRunnable {PrivateBlockingqueue<task>queue;  PublicTaskrunner (blockingqueue<task>queue) {          This. Queue =queue; }     Public voidrun () {Try {              while(true) {Task Task= Queue.take (10, 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.

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
UblicclassPrimeproducerextendsThread {Private FinalBlockingqueue<biginteger>queue; Primeproducer (Blockingqueue<BigInteger>queue) {         This. Queue =queue; }     Public voidrun () {Try{BigInteger P=Biginteger.one;  while(!Thread.CurrentThread (). isinterrupted ()) Queue.put (P=p.nextprobableprime ()); } Catch(Interruptedexception consumed) {/*Allow thread to exit*/        }    }     Public voidCancel () {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.niothe 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
 PublicTask Getnexttask (blockingqueue<task>queue) {    Booleaninterrupted =false; Try {         while(true) {            Try {                returnQueue.take (); } Catch(Interruptedexception e) {interrupted=true; //fall through and retry            }        }    } finally {        if(interrupted) thread.currentthread (). interrupt (); }}
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.

Handling Interruptedexception--brian Goetz

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.