How to handle InterruptedException?
在线程编程中往往会遇到这个异常,但是我们该怎么处理这个异常呢?今天搜了Google,摘下来:
http://www.artima.com/forums/flat.jsp?forum=276&thread=161312
In his latest DeveloperWorks article, Brian Goetz discusses strategies for dealing with InterruptedException. The article shows how swallowing InterruptedException can lead to unpredictable application behavior, and outlines strategies for cancellable tasks as a way to manage this aspect of Java concurrency.
Most developers deal with InterruptedException
by simply swallowing it. Brian Goetz in his recent DeveloperWorks article shows why this is wrong:
The worst thing you can do with InterruptedException
is swallow it—catch it and neither rethrow it nor reassert the thread's interrupted status. The standard approach to dealing with an exception you didn't plan for—catch it and log it—also counts as swallowing the interruption because code higher up on the call stack won't be able to find out about it. (Logging InterruptedException
is also just silly because by the time a human reads the log, it is too late to do anything about it.)
The article explains the notion of a blocking method:
When a method throws InterruptedException
... it is telling you that it is a blocking method and that it will make an attempt to unblock and return early—if you ask nicely... The completion of a blocking method ... is ... dependent on some external event, such as timer expiration, I/O completion, or the action of another thread (releasing a lock, setting a flag, or placing a task on a work queue). Ordinary methods complete as soon as their work can be done, but blocking methods are less predictable because they depend on external events. Blocking methods can compromise responsiveness because it can be hard to predict when they will complete.
A method that calls a blocking method becomes a blocking method as well. The main benefit of InterruptedException
is the ability to deal with blocking methods by allowing cancellation of such methods from another thread and then letting the interrupted thread perform cleanup work.
For instance, in a GUI application, the user might be given a chance to interrupt a blocking method, or in a server application a monitoring component can cancel a task given some operational conditions, such as a timeout. When a caller interrupts a blocking method, the blocking method will have an opportunity to perform cleanup work by handling InterruptedException
.
If no special cleanup is required, the article suggests that the blocking method should handle InterruptedException
by re-interrupting the current thread:
public void run() {
try {
while (true) {
Task task = queue.take(10, TimeUnit.SECONDS);
task.execute();
}
}
catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
The main reason for doing is that the interruption request that resulted in InterruptedException
may have multiple recipients:
The standard thread pool (ThreadPoolExecutor
) worker thread implementation is responsive to interruption, so interrupting a task running in a thread pool may have the effect of both canceling the task and notifying the execution thread that the thread pool is shutting down. If the task were to swallow the interrupt request, the worker thread might not learn that an interrupt was requested, which could delay the application or service shutdown.
What do you think of the article's conclusions? What are your strategies for handling blocking methods, and how do you deal with InterruptedException
in your code?
http://203.208.37.132/search?q=cache:ZfdrN3gjDEoJ:michaelscharf.blogspot.com/2006/09/dont-swallow-interruptedexception-call.html+How+to+handle+InterruptedException&cd=6&hl=zh-CN&ct=clnk&gl=cn&st_usg=ALhdy28Tiz_OPdS_v5AmbeiF2ZRExDzpSQ
Have you ever written the following code?
try {
doSomething();
} catch(InterruptedException
swallowed) {
// BAD BAD PRACTICE, TO IGNORE THIS EXCEPTION
// just logging is also not a useful option here....
}
I have! I newer knew what the heck to do with those annoying
InterruptedException when I simply wanted to call Thread.sleep(..). What is this
InterruptedException ? Why is it thrown? Why can't I ignore it?
Before I explain the whys, here is what you should do (if you don't re-throw):
try {
doSomething();
} catch(InterruptedException
e) {
// Restore the interrupted status
Thread.currentThread().interrupt()
;
}
What is the InterruptedException ?
There is no way to simply stop a running thread in java (
don't even consider using the deprecated method
stop() ). Stopping threads is cooperative in java. Calling
Thread.interrupt() is a way to tell the thread to stop what it is doing. If the thread is in a blocking call, the blocking call will throw an
InterruptedException , otherwise the interrupted flag of the tread will be set. A Thread or a Runnable that is interruptable should check from time to time
Thread.currentThread().isInterrupted() . If it returns true, cleanup and return.
Why is it InterruptedException thrown?
The problem is that blocking calls like
sleep() and
wait() , can take very long till the check can be done. Therefore they throw an
InterruptedException . However the isInterrupted is cleared when the
InterruptedException is thrown! (I have some vague idea why this is the case, but for whatever reason this is done, that is how it is!)
Why can't InterruptedException be simply ignored?
It should be clear by now: because
ignoring an InterruptedException means resetting the interrupted status of the thread . For example, worker threads take runnable from a queue and execute they may check the interrupted status periodically. If you swallow it the thread would not know that it was interrupted and would happily continue to run.
Some more thoughts
Unfortunately it is not specified that Thread.interrupt() can only be used for cancellation. It can be used for anything that requires to set a flag on a thread. So, ending your task or runnable early might be the wrong choice, if the interrupted status is used for something else. But common practice is to use it for cancellation. But even if it is used for something else, you code does not have the right to reset the interrupt flag (unless you are the owner of the thread).
To learn more read the nice article
Dealing with InterruptedException by Brian Goetz.
Or read
Java Concurrency in Practice By BriaBrian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, and Doug Lea. It's a great book!
If you program in java 5 this book is a must read! . I bought the book after I read Brians artikle. I have not yet read the entire book, but what I have read impresses me. It gives a lot of theorie and options. Very competent and complete, but I'm missing a set of simple patterns for concurrent programming. I'm looking forward to Doug Leas 3rd edition of
Concurrent Programming in Java
Summary: If you don't know what to do with an InterruptedException call Thread.currentThread().interrupt()
11 comments:
AlBlue said...
Firstly, .interrupt() does not mean 'quit'. It means, well, interrupt. It's a way of notifying that your thread needs to do something, be it start again, cancel, quit, reiterate, reload config file ... it's basically the same as kill -HUP, which is interpreted in a number of different ways depending on the program.
Secondly, why catch it at all? Propagate the exception upwards. That's good practice for pretty much any exception that you don't know what to do with.
Anonymous said...
Wow - get a clue dude. That is the exactly wrong advice of what to do regarding InterruptedException !!!
Here's the correct answer:
1) DON'T call Thread.currentThread().interrupt()!!! Your thread was already interrupted, which was why you received the InterruptedException in the first place. Why one earth would you want to interrupt it again?!?!? Not to mention that you're telling the thread that was already interrupted to then go and interrupt itself!!!! Duh!
2) If you've coded your thread loops properly with a termination condition (e.g., while (!finished)) then doing nothing when you receive an InterruptedException is a perfectly reasonable thing to do. You told a thread to block on some operation until some condition was met (e.g., it was given some data). However, someone else wants to interrupt the operation before that condition was met. (Most likely a thread shut-down process of some sort.) So your thread gets woken up without its required condition being met. So what? Check whether the thread is supposed to terminate or keep running. If it should terminate (i.e., it's being shut down) then let it exit the thread loop and die. If not, then let it loop again and go back to blocking.
Sheesh! Have some clue what you're talking about before you write something like this in public.
Michael Scharf said...
Alex, I agree, re-trow is the best solution. But there are cases, when you cannot propagate the interrupted exception. In these cases it would get swallowed if you don't re-throw and you don't call interrupt.
But if you don't know what the meaning of the -HUP signal is, you should better not swallow it.
Michael
Michael Scharf said...
Anonymous, good that you are anonymous, because you should maybe read the documentation before you blame me of not understanding what I am talking about.
1) In the documentation of Thread.sleep(long) (as in any other method that throws InterruptedExceptin) it says: "The interrupted status of the current thread is cleared when this exception is thrown".
2) I agree, that it is not reliable to use interrupt to terminate your operation. However, the interrupt flag might mean something to someone outside your scope. By catching the exception and not restoring the interrupted state you are swallowing important information.....
Sheesh! Have some clue what you're talking about before you write something like this in public. ;-)
Virtualwarp said...
There is another solution to handle InterruptedException when you cannot throw it. It's possible to wrap the InterruptedException into a RuntimeExcpetion. This might help in cases where you don't want to interrupt the whole thread.
Villane said...
I think Anonymous is at least partly right. The interrupted status doesn't seem like very reliable information exactly because how many complex scenarios there are that can clear it. For example, one query method also clears it:
"public static boolean interrupted()
Tests whether the current thread has been interrupted. The interrupted status of the thread is cleared by this method. ..."
I think it's better to use a custom property for any meaningful thread statuses. Of course, this usually means some kind of common base class or interface for threads, which is also not a great solution.
Michael Scharf said...
Villane,
it's true that the Thread.interrupt() is not really reliable, because its not well defined how to use it. But it is the *only* way to terminate a blocking call..
Michael
Anonymous said...
Hello,
I find this discussion very useful. I have coded a garbage collector which runs in a separate thread and removes objects from a cache. The code is as follows:
public void run(){
while (true){
try{
Thread.sleep(SOME_DURATION);
cache.lock.writeLock().lock();
//clean up the cache
cache.lock.writeLock().unlock();
}
catch(InterruptedException ie){
}
}//while
}
I think I am okay with not adding the Thread.currentThread().interrupt() in the catch block because I don't want the garbage collector to be turned off during program execution. I wonder though if the thread could ever be interrupted by some process that has been asked to terminate the thread...for example a program from which you can gracefully shut down a running application. You would not know the source of the InterruptedException . If the code above was interrupted by a program which wants to shut down the thread, then the while loop should be terminated. If some action in the loop caused the interrupt, then the loop should continue, and be given a chance to repeat the action at a later time.
If possible, please let me know the possible sources which would invoke the interrupt and if my concerns are valid.
Thanks so much.
-Paula
Michael Scharf said...
Paula,
if you create the thread and you have control over the thread, then you can swallow the exception. You have somehow to define your own mechanism to shut down the thread. If you want to stop the Thread, while it is sleeping for SOME_DURATION, you'd have to call the method Thread.interrupt(). But if you swallow the interrupt you won't get out of your infinite while loop. If you use the interrupt state of your thread as mechanism to shut it down your loop would look like:
while(!isInterrupted()) {
try {
Thread.sleep(SOME_DURATION);
//clean up the cache
} catch(InterruptedException ie){
break;
}
}
But then you should make sure that no code that you call from within the loop is swallowing the interrupt exception. And that is really the problem. Because there is so much code out there that swallows InterruptedException , using the thread interrupt mechanism is not really reliable....
Michael
thierno said...
hello every body.
I would like to know how i could stop my threads with a boolean .
thierno said...
public class myThread implements Runnable{
private Thread T1;
public void Start ( ) {
myThread = new Thread( this );
myThread.start();
}
public void run(){
try{
for (int i=0; i< someThing; i++){
traitement();
Thread.sleep(1000);
}//end for
catch(InterruptedException e){}
}//end try
}//end run
// and this my method to stop threads but i can't stop it. NEED HELP.
boolean finish = true;
synchronise public void stopThread(){
finish = true;
while(finish){
if (T1.isAlive()){
T1.interrupt();
T1 = null;
}
}
}
}