I want a piece of code to run as long as the thread isn't interrupted. Currently what I'm doing is this:
while(!Thread.interrupted()){
// .. some code
try {
Thread.sleep(4000);
} catch(InterruptedException ex){
break;
}
// .. some more code
}
My question is: is this good practice? Is it appropriate use of interrupt?
Yes, I think this is the very purpose of interrupt(), so it seems like a legitimate usage.
Conceptually this is on the right track. There are some details that could be improved, though.
What's right about this is that the thread interruption mechanism is being used to tell the thread to do something else, and the thread can respond how it pleases at a time of its choosing. In this case, catching InterruptedException from Thread.sleep() and breaking out of the loop is an entirely reasonable thing to do. It's certainly much preferable to what is usually done, which is to ignore the exception entirely. (This is usually wrong.)
What might be an issue is that the loop condition also checks whether the thread has been interrupted. This might be a problem, depending on what some code and some more code are doing. Your system might be left in different states depending on which chunks of code have been executed when the interrupt is detected.
Unless one iteration of your loop runs for a really long time (aside from the sleep), it's usually only necessary for there to be a single interruption point in a loop. In this case, if the thread is interrupted while it's doing some code processing, an InterruptedException will be generated immediately upon the call to Thread.sleep(). So you could just change the loop condition to while (true) and have the catch-block break out of the loop. (If you do this, you should also reassert the interrupt bit; see below.)
Alternatively, if you only want to check for interrupts at the top of the loop, you could do this:
while (!Thread.interrupted()) {
// .. some code
try {
Thread.sleep(4000L);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
// .. some more code
}
This arranges there to be only a single exit point from the loop, which might makes the code easier to reason about.
Note the technique used here is to reassert the interrupt bit on the thread after having caught InterruptedException. The general rule about handling interrupts is that either the interrupt bit should be reasserted, or an InterruptedException should be propagated. If neither is done, then the calling code might end up blocked in a subsequent wait() call, with no knowledge that it had ever been interrupted. That's usually an error.
Good practice is to use the newer higher level APIs such as an ExecutorService instead. You shouldn't use the lower level APIs such as threads or synchronize or wait/notify.
Related
What is the difference between the following ways of handling InterruptedException? What is the best way to do it?
try{
//...
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
OR
try{
//...
} catch(InterruptedException e) {
throw new RuntimeException(e);
}
EDIT: I'd like to also know in which scenarios are these two used.
What is the difference between the following ways of handling InterruptedException? What is the best way to do it?
You've probably come to ask this question because you've called a method that throws InterruptedException.
First of all, you should see throws InterruptedException for what it is: A part of the method signature and a possible outcome of calling the method you're calling. So start by embracing the fact that an InterruptedException is a perfectly valid result of the method call.
Now, if the method you're calling throws such exception, what should your method do? You can figure out the answer by thinking about the following:
Does it make sense for the method you are implementing to throw an InterruptedException? Put differently, is an InterruptedException a sensible outcome when calling your method?
If yes, then throws InterruptedException should be part of your method signature, and you should let the exception propagate (i.e. don't catch it at all).
Example: Your method waits for a value from the network to finish the computation and return a result. If the blocking network call throws an InterruptedException your method can not finish computation in a normal way. You let the InterruptedException propagate.
int computeSum(Server server) throws InterruptedException {
// Any InterruptedException thrown below is propagated
int a = server.getValueA();
int b = server.getValueB();
return a + b;
}
If no, then you should not declare your method with throws InterruptedException and you should (must!) catch the exception. Now two things are important to keep in mind in this situation:
Someone interrupted your thread. That someone is probably eager to cancel the operation, terminate the program gracefully, or whatever. You should be polite to that someone and return from your method without further ado.
Even though your method can manage to produce a sensible return value in case of an InterruptedException the fact that the thread has been interrupted may still be of importance. In particular, the code that calls your method may be interested in whether an interruption occurred during execution of your method. You should therefore log the fact an interruption took place by setting the interrupted flag: Thread.currentThread().interrupt()
Example: The user has asked to print a sum of two values. Printing "Failed to compute sum" is acceptable if the sum can't be computed (and much better than letting the program crash with a stack trace due to an InterruptedException). In other words, it does not make sense to declare this method with throws InterruptedException.
void printSum(Server server) {
try {
int sum = computeSum(server);
System.out.println("Sum: " + sum);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // set interrupt flag
System.out.println("Failed to compute sum");
}
}
By now it should be clear that just doing throw new RuntimeException(e) is a bad idea. It isn't very polite to the caller. You could invent a new runtime exception but the root cause (someone wants the thread to stop execution) might get lost.
Other examples:
Implementing Runnable: As you may have discovered, the signature of Runnable.run does not allow for rethrowing InterruptedExceptions. Well, you signed up on implementing Runnable, which means that you signed up to deal with possible InterruptedExceptions. Either choose a different interface, such as Callable, or follow the second approach above.
Calling Thread.sleep: You're attempting to read a file and the spec says you should try 10 times with 1 second in between. You call Thread.sleep(1000). So, you need to deal with InterruptedException. For a method such as tryToReadFile it makes perfect sense to say, "If I'm interrupted, I can't complete my action of trying to read the file". In other words, it makes perfect sense for the method to throw InterruptedExceptions.
String tryToReadFile(File f) throws InterruptedException {
for (int i = 0; i < 10; i++) {
if (f.exists())
return readFile(f);
Thread.sleep(1000);
}
return null;
}
This post has been rewritten as an article here.
As it happens I was just reading about this this morning on my way to work in Java Concurrency In Practice by Brian Goetz. Basically he says you should do one of three things
Propagate the InterruptedException - Declare your method to throw the checked InterruptedException so that your caller has to deal with it.
Restore the Interrupt - Sometimes you cannot throw InterruptedException. In these cases you should catch the InterruptedException and restore the interrupt status by calling the interrupt() method on the currentThread so the code higher up the call stack can see that an interrupt was issued, and quickly return from the method. Note: this is only applicable when your method has "try" or "best effort" semantics, i. e. nothing critical would happen if the method doesn't accomplish its goal. For example, log() or sendMetric() may be such method, or boolean tryTransferMoney(), but not void transferMoney(). See here for more details.
Ignore the interruption within method, but restore the status upon exit - e. g. via Guava's Uninterruptibles. Uninterruptibles take over the boilerplate code like in the Noncancelable Task example in JCIP § 7.1.3.
What are you trying to do?
The InterruptedException is thrown when a thread is waiting or sleeping and another thread interrupts it using the interrupt method in class Thread. So if you catch this exception, it means that the thread has been interrupted. Usually there is no point in calling Thread.currentThread().interrupt(); again, unless you want to check the "interrupted" status of the thread from somewhere else.
Regarding your other option of throwing a RuntimeException, it does not seem a very wise thing to do (who will catch this? how will it be handled?) but it is difficult to tell more without additional information.
The correct default choice is add InterruptedException to your throws list. An Interrupt indicates that another thread wishes your thread to end. The reason for this request is not made evident and is entirely contextual, so if you don't have any additional knowledge you should assume it's just a friendly shutdown, and anything that avoids that shutdown is a non-friendly response.
Java will not randomly throw InterruptedException's, all advice will not affect your application but I have run into a case where developer's following the "swallow" strategy became very inconvenient. A team had developed a large set of tests and used Thread.Sleep a lot. Now we started to run the tests in our CI server, and sometimes due to defects in the code would get stuck into permanent waits. To make the situation worse, when attempting to cancel the CI job it never closed because the Thread.Interrupt that was intended to abort the test did not abort the job. We had to login to the box and manually kill the processes.
So long story short, if you simply throw the InterruptedException you are matching the default intent that your thread should end. If you can't add InterruptedException to your throw list, I'd wrap it in a RuntimeException.
There is a very rational argument to be made that InterruptedException should be a RuntimeException itself, since that would encourage a better "default" handling. It's not a RuntimeException only because the designers stuck to a categorical rule that a RuntimeException should represent an error in your code. Since an InterruptedException does not arise directly from an error in your code, it's not. But the reality is that often an InterruptedException arises because there is an error in your code, (i.e. endless loop, dead-lock), and the Interrupt is some other thread's method for dealing with that error.
If you know there is rational cleanup to be done, then do it. If you know a deeper cause for the Interrupt, you can take on more comprehensive handling.
So in summary your choices for handling should follow this list:
By default, add to throws.
If not allowed to add to throws, throw RuntimeException(e). (Best choice of multiple bad options)
Only when you know an explicit cause of the Interrupt, handle as desired. If your handling is local to your method, then reset interrupted by a call to Thread.currentThread().interrupt().
To me the key thing about this is: an InterruptedException is not anything going wrong, it is the thread doing what you told it to do. Therefore rethrowing it wrapped in a RuntimeException makes zero sense.
In many cases it makes sense to rethrow an exception wrapped in a RuntimeException when you say, I don't know what went wrong here and I can't do anything to fix it, I just want it to get out of the current processing flow and hit whatever application-wide exception handler I have so it can log it. That's not the case with an InterruptedException, it's just the thread responding to having interrupt() called on it, it's throwing the InterruptedException in order to help cancel the thread's processing in a timely way.
So propagate the InterruptedException, or eat it intelligently (meaning at a place where it will have accomplished what it was meant to do) and reset the interrupt flag. Note that the interrupt flag gets cleared when the InterruptedException gets thrown; the assumption the Jdk library developers make is that catching the exception amounts to handling it, so by default the flag is cleared.
So definitely the first way is better, the second posted example in the question is not useful unless you don't expect the thread to actually get interrupted, and interrupting it amounts to an error.
Here's an answer I wrote describing how interrupts work, with an example. You can see in the example code where it is using the InterruptedException to bail out of a while loop in the Runnable's run method.
I just wanted to add one last option to what most people and articles mention. As mR_fr0g has stated, it's important to handle the interrupt correctly either by:
Propagating the InterruptException
Restore Interrupt state on Thread
Or additionally:
Custom handling of Interrupt
There is nothing wrong with handling the interrupt in a custom way depending on your circumstances. As an interrupt is a request for termination, as opposed to a forceful command, it is perfectly valid to complete additional work to allow the application to handle the request gracefully. For example, if a Thread is Sleeping, waiting on IO or a hardware response, when it receives the Interrupt, then it is perfectly valid to gracefully close any connections before terminating the thread.
I highly recommend understanding the topic, but this article is a good source of information: http://www.ibm.com/developerworks/java/library/j-jtp05236/
I would say in some cases it's ok to do nothing. Probably not something you should be doing by default, but in case there should be no way for the interrupt to happen, I'm not sure what else to do (probably logging error, but that does not affect program flow).
One case would be in case you have a task (blocking) queue. In case you have a daemon Thread handling these tasks and you do not interrupt the Thread by yourself (to my knowledge the jvm does not interrupt daemon threads on jvm shutdown), I see no way for the interrupt to happen, and therefore it could be just ignored. (I do know that a daemon thread may be killed by the jvm at any time and therefore are unsuitable in some cases).
EDIT:
Another case might be guarded blocks, at least based on Oracle's tutorial at:
http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
I was reading about ways to end a thread in https://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html, which is a link I found from the question How do you kill a thread in Java?
In the first link, they first discuss using a volatile variable to signal to the thread that you want to terminate. The thread is supposed to check this variable and cease operation if the variable has a value that means cease (e.g. if it is null). So to terminate the thread, you would set that variable to null.
Then they discuss adding interrupts to help with threads that block for long periods of time. They give the following example of a stop() method that sets the volatile variable (waiter) to null and then ALSO throws an interrupt.
public void stop() {
Thread moribund = waiter;
waiter = null;
moribund.interrupt();
}
I am just wondering, why would you need both? Why not ONLY use interrupt(), and then handle it properly? It seems redundant to me.
(First part of this is in general, arguably I was not paying attention to the specifics of the question. Skip to the end for the part that addresses the techspec discussed in the question.)
There is no good technical reason. This is partly about human limitations and partly about confusing api design.
First consider application developers’ priority is creating working code that solves business problems. Thoroughly learning low level apis like this gets lost in the rush to get work done.
Second there’s a tendency when you’re learning things to get to a good enough state and leave it there. Things like threading and exception handling are back-of-the-book topics that get neglected. Interruption is a back of the book topic for threading books.
Now imagine a codebase worked on by multiple people with varying skill level and attention to detail, who may forget that throwing InterruptedException from wait and sleep resets the interrupt flag, or that interrupted isn’t the same as isInterrupted, or that InterruptedIoException resets the interrupt flag too. If you have a finally block that catches IOException, you may miss that InterruptedException is a subclass of IOException and you could be missing out on restoring the interrupt flag. Probably people in a hurry decided to hell with it, I can’t count on this interrupted flag
Is it right? No.
The hand rolled flag doesn’t help with short circuiting wait or sleep the way interruption does.
the Java 5 concurrency tools expect tasks to use interruption for cancellation. Executors expect tasks submitted to them to check for interruption in order to quit gracefully. Your tasks may use other components, like a blocking queue. That queue needs to be able to respond to interruption, the thing using it needs to be aware of the interruption. The handrolled flag doesn’t work for this since the java 5 classes can’t know about it.
Having to use interruption because you’re using tools that expect it, but not having confidence in the flag value due to unmanageable technicalities, would lead to this kind of code.
(end of rant, now actually responding to the specific techspec example)
OK, looking at this techguide article in particular. Three things stand out:
1) it's not making use of interruption at all, except to cut the sleep time short. Then it just squelches the exception, and doesn't bother to restore the flag or check it. You could use the InterruptedException to terminate by catching it outside the while loop, but that's not what this does. This seems like a strange way to do this.
2) as the example is fleshed out it becomes clear the flag is being used to turn the waiting on and off. Somebody might use interruption for this but it's not idiomatic. So having a flag is ok here.
3) this is a toy example in a techguide. Not all the Oracle content is as authoritative as the techspecs or the API documentation. Some tutorials have misstatements or are incomplete. It might be the reason the code was written like this was that the author figured readers would not be familiar with how interruption worked and it was better to minimize its usage. Technical writers have been known to make choices like that.
If I rewrote this to use interruption I would still keep the flag; I'd use interrupt to terminate, and use the flag for suspend/resume functionality.
Please see this documentation.
Your thread should check thread.isInterrupted() status, for example:
Thread myThread = new Thread() {
#Override
public void run() {
while (!this.isInterrupted()) {
System.out.println("I'm working");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//We would like also exit from the thread
return;
}
}
}
};
And when you would like to stop the thread, you should invoke
myThread.interrupt();
Besides we can use static method Thread.interrupted() that also checks the status but after that, the method clears it and you have to invoke again myThread.interrupt() to set the status again. But I don't recommend to use Thread.interrupted() method.
This approach helps gracefully stop the thread.
So I also do not see any reasons to use an additional volatile variable.
The same behavior can be reached via additional volatile flag as in #lexicore's answer, but I think it is redundant code.
#NathanHughes is completely right, but I am going to rephrase his long answer into few words: third-party code.
This is not just about "dumb junior developers", — at some point in application's life you will be using lots of third-party libraries. Those libraries will not gentlemanly respect your assumptions about concurrency. Sometimes they will silently reset interruption flag. Using separate flag solves that.
No, you can not get rid of third-party code and call it a day.
Suppose, that you are writing a library, — for example, ThreadPoolExecutor. Some of the code inside your library needs to handle interruption… Or even unconditionally reset the interruption flag. Why? Because previous Runnable is done, and a new Runnable is on the way. Unfortunately, at that point there may be a stale interruption flag, that was aimed… wait, whom was it for again? It could have been addressed for previous Runnable or for new (not yet running) Runnable, — there is no way to tell. And this is why you add isCancelled method to FutureTask. And unconditionally reset interruption flag before executing new Runnable. Sounds familiar?
Thread#interrupt is completely detached from the actual work units, running on that thread, so adding an additional flag is necessary. And once you have started doing so, you have to do that all the way — up to the outermost and down to the innermost work unit. In effect, running unknown user-supplied code on your threads makes Thread#interrupted unreliable (even if Thread#interrupt still works fine!)
I got two threads: A and B.
There is an endless loop in thread A:
while ( true ) {
// Do something
}
Thread B is monitoring some state of interest to me. When the state changes, I want thread A to stop any further execution.
The following solution is not sufficient (setting keepRunning to true with method in A which is called from B):
while ( keepRunning) {
// Do something
}
I can't wait for the body of the loop to be executed before thread A is halted - I want the execution of the methods called in the loop to be interrupted.
Is there a way to achieve the above functionality?
You can do a few point fixes, like checking keepRunning at key points in A's loop. You could also interrupt thread A, which only helps you if it calls any methods that throw InterruptedException.
But you can't just have thread A stop dead in its tracks, and for good reason: this would be prone to deadlock. There used to be a methods Thread.stop and Thread.suspend that did just that, and they've been deprecated because of those dangers. Starting in Java 8, that method throws UnsupportedOperationException.
Basically, a thread has to stop itself. It can do so at the request of other threads (communicated by a field like keepRunning or by an interrupt), but it has to do it. One thread can't directly stop another.
You can interrupt the Thread at any point, however this only triggers an InterruptedException in the method should check this.
You can attempt to stop a thread however, this is an unsafe operation as it can occur at any point and unless you are very careful, this can leave memory in an inconsistent state. If you are going to be that careful, you may as well add some checks and stop the code early.
This is a really bad idea, because what happens when there are critical resources open, like e.g. a file? It won't be closed:
while (keepRunning) {
openFile();
// gets stopped here
closeFile();
}
This can of course happen with other things as well, OS processes, network sockets, anything. You see why this is a bad idea?
You should instead redesign the code in the loop to check for the condition more often and break and cleanup if the condition doesn't hold true anymore.
while (keepRunning) {
openFile();
doLongOperation();
if (!keepRunning) {
closeFile();
break; // or return
}
doAnotherLongOperation();
closeFile();
}
This way, you don't lose the safety, while being able to stop it faster.
You might not actually use precious resources, but in any case you should tell us more details so we can give a more precise answer.
I've come across the code below, and I'm wondering if it does exactly what I think it does:
synchronized(sObject) {
mShouldExit = true;
sObject.notifyAll()
while (!mExited) {
try {
sObject.wait();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
About the context: there is another thread that checks for mShouldExit (inside the sObject monitor) and will exit in that case.
This does not look to be a correct pattern to me. If an interrupt happens, it will set the interrupted status again, so when it returns to sObject.wait(), another InterruptedException will come etc. etc. etc. Therefore, it can never go to truly waiting state (sObject.wait()) i.e. it will never release the sObject monitor. This may result in an infinite loop, as the other thread cannot set mExiting to true, because it can never enter sObject's monitor. (So I think that the interrupt() call is an error, it must not be used here.) Am I missing something?
Note that the code snippet is a part of the official Android framework source code.
UPDATE: actually, the situation is worse, because the same pattern is used in Android when your GL rendering starts. The official source code of GLSurfaceView.GLThread.surfaceCreated():
public void surfaceCreated() {
synchronized(sGLThreadManager) {
if (LOG_THREADS) {
Log.i("GLThread", "surfaceCreated tid=" + getId());
}
mHasSurface = true;
sGLThreadManager.notifyAll();
while((mWaitingForSurface) && (!mExited)) {
try {
sGLThreadManager.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
You can reproduce the bug in a similar way: make sure your UI thread has its interrupted status flag yet, then add your GLSurfaceView and start the GL rendering (via setRenderer(...), but on some devices, make sure your GLSurfaceView has Visibility.VISIBLE status, otherwise rendering will not start).
If you follow the above steps, your UI thread will end up in an infinite loop, because the above-quoted code will keep generating an InterruptedException (due to wait()) and therefore the GL thread will never be able to set mWaitingForSurface to false.
According to my tests, it seems that such an infinite loop will also result in an endless sequence of GC_CONCURRENT garbage collection (or, at least, such messages in logcat). Interesting, someone had an unknown poorly-defined issue on stackoverflow earlier which might be related:
How to solve GC_concurrent freed?
Isn't it possible that perhaps his UI thread had its interrupted flag set to true, and he was using a GLSurfaceView for the map he mentions? Just an assumption, a possible scenario.
Short version: That code is wrong, and will cause an infinite loop (I still have a doubt, but may depend on JVM implementations). Setting the interrupt status is the right thing to do, but it should then exit the loop, eventually checking that same interruption status using Thread.isInterrupted().
Long version for the casual reader:
The problem is how to stop a thread that is currently executing some work, in response to a "Cancel" button from the user or because of some other application logic.
Initially, Java supported a "stop" method, that preemptively stopped a thread. This method has been demonstrated to be unsafe, cause didn't give the stopped thread any (easy) way to clean up, release resources, avoid exposing partially modified objects and so on.
So, Java evolved to a "cooperative" Thread "interruption" system. This system is quite simple : a Thread is running, someone else calls "interrupt" on it, a flag is set on the Thread, it's Thread responsibility to check if it has been interrupted or not and act accordingly.
So, correct Thread.run (or Runnable.run, of Callable etc..) method implementation should be something like :
public void run() {
while (!Thread.getCurrentThread().isInterrupted()) {
// Do your work here
// Eventually check isInterrupted again before long running computations
}
// clean up and return
}
This is fine as long as all the code your Thread is executing is inside your run method, and you never call something that blocks for a long time ... which is often not the case, cause if you spawn a Thread is because you have something long to do.
The simplest method that block is Thread.sleep(millis), it's actually the only thing it does : it blocks the thread for the given amount of time.
Now, if the interrupt arrives while your thread is inside Thread.sleep(600000000), without any other suport, it would take a lot for it to arrive to the point where it checks isInterrupted.
There are even situations where your thread would never exit. For example, your thread is computing something and sending results to a BlockingQueue with a limited size, you call queue.put(myresult), it will block until the consumer free some space in the queue, if in the mean time the consumer has been interrupted (or died or whatever), that space will never arrive, the method will not return, the check on .isInterrupted will never be performed, your thread is stuck.
To avoid this situation, all (most) methods that interrupt the thread (should) throw InterruptedException. That exception simply tells you "I was waiting for this and that, but in the meanwhile the thread as been interrupted, you should do cleanup and exit as soon as possible".
As with all exceptions, unless you know what to do, you should re-throw it and hope that someone above you in the call stack knows.
InterruptedExceptions are even worse, since when they are thrown the "interrupted status" is cleared. This means that simply catching and ignoring them will result in a thread that usually does not stop :
public void run() {
while (!Thread.getCurrentThread().isInterrupted()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// Nothing here
}
}
}
In this example, if the interrupt arrives during the sleep() method (which is 99.9999999999% of the time), it will throw InterruptedException, clear the interrupt flag, then the loop will continue since the interrupt flag is false, and the thread will not stop.
That's why if you implement your "while" correctly, using .isInterrupted, and you really need to catch InterruptedException, and you don't have anything special (like cleanup, return etc..) to do with it, least that you can do is set the interrupt flag again.
The problem in the code you posted is that the "while" relies solely on mExited to decide when to stop, and not ALSO on isInterrupted.
while (!mExited && !Thread.getCurrentThread().isInterrupted()) {
Or it could exit when interrupted :
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return; // supposing there is no cleanup or other stuff to be done
}
Setting the isInterrupted flag back to true is also important if you don't control the Thread. For example, if you are in a runnable which is being executed in a thread pool of some kind, or inside any method anywhere you don't own and control the thread (a simple case : a servlet), you don't know if the interruption is for "you" (in the servlet case, the client closed the connection and the container is trying to stop you to free the thread for other requests) or if it's targeted at the thread (or system) as a whole (the container is shutting down, stopping everything).
In that situation (which is 99% of the code), if you cannot rethrow the InterruptedException (which is, unfortunately, checked), the only way to propagate up the stack to the thread pool that the thread has been interrupted, is setting the flag back to true before returning.
That way, it will propagate up the stack, eventually generating more InterruptedException's, up to the thread owner (be it the jvm itself, of an Executor, or any other thread pool) that can react properly (reuse the thread, let it die, System.exit(1) ...)
Most of this is covered in chapter 7 of Java Concurrency in Practice, a very good book that I recommend to anyone interested in computer programming in general, not just Java, cause the problems and the solutions are similar in many other environments, and explanations are very well written.
Why Sun decided to make InterruptedException checked, when most documentation suggests to rethrow it mercilessly, and why they decided to clear the interrupted flag when throwing that exception, when the proper thing to do is setting it to true again most of the time, remains open for debate.
However, if .wait releases the lock BEFORE checking for the interrupt flag, it open a small door from another thread to modify the mExited boolean. Unfortunately the wait() method is native, so source of that specific JVM should be inspected. This does not change the fact that the code you posted is coded poorly.
I have a long running task, something like:
public void myCancellableTask() {
while ( someCondition ) {
checkIfCancelRequested();
doSomeWork();
}
}
The task can be cancelled (a cancel is requested and checkIfCancelRequested() checks the cancel flag). Generally when I write cancellable loops like this, I use a flag to indicate that a cancel has been requested. But, I know I could also use Thread.interrupt and check if the thread has been interrupted. I'm not sure which would be the preferred approach and why, thoughts?
thanks,
Jeff
One problem with using interrupt is that if you do not control all code being executed, you run the risk of the interrupt not working "properly" because of someone else's broken understanding of how to handle interrupts in their library. That is the API invisibly exports an API around its handling of interrupts which you become dependent on.
In your example, suppose doSomeWork was in a 3rd-party JAR and looks like:
public void doSomeWork() {
try {
api.callAndWaitAnswer() ;
}
catch (InterruptedException e) { throw new AssertionError(); }
}
Now you have to handle an AssertionError (or whatever else the library you are using might throw). I've seen experienced developers throw all sorts of nonsense on receiving interrupts! On the other hand, maybe the method looked like this:
public void doSomeWork() {
while (true) {
try {
return api.callAndWaitAnswer() ;
}
catch (InterruptedException e) { /* retry! */ }
}
}
This "improper handling" of interrupt causes your program to loop indefinitely. Again, don't dismiss this as ridiculous; there are a lot of broken interrupt handling mechanisms out there.
At least using your own flag will be completely invisible to any 3rd-party libraries.
Interrupt will blast the thread out of a list of specified wait conditions. Your own cancel flag will not. If you want to interrupt waits on IO and events, use interrupt. Otherwise use your own.
It depends on the doSomeWork() implementation. Is that pure computation or does it (at any point) involve blocking API (such as IO) calls? Per bmargulies's answer, many blocking APIs in JDK are interruptible and will propagate the interrupted exception up the stack.
So, if the work entails potentially blocking activities, you need'll to take interrupts into consideration even if you decide to control the process using a flag, and should appropriately catch and handle/propagate the interrupts.
Beyond that, if relying on a flag, make sure your flag is declared with volatile semantics.
I think that it's a matter of preference in most cases.
Personally I would go for the hand-made flag. It gives you more control - for example, this way you make sure that your thread doesn't leave some other object in an inconsistent state.
Besides, if performance is really critical, bear in mind that using exceptions has an overhead (even if it's negligible in 99% of the cases).
First, let's take a look at the usage conditions.
If we have a thread pool and use interruption as the cancellation mechanism, we can only interrupt the worker threads through the pool. In other words, we can't directly invoke Thread.interrupt since we don't own the threads. So, we must acquire a Future and invoke Future.cancel. Or we must call ExecutorService.shutdownNow to cancel all tasks interrupting the busy threads. In the first case, it requires some bookkeeping on our side to hold the Future handles. So the application must keep new tasks and remove the old ones.
On the other hand, if you use a global cancellation flag, we can cancel/stop multiple tasks from a central place without additional bookkeeping. But if we want to cancel an individual task - similar to invoking Future.cancel - we must store a cancellation flag for each task.
Secondly, let's examine the general convention.
Java class libraries generally interpret a thread interrupt as a cancellation request. For example, LinkedBlockingQueue.take can make our program block. But when the current thread is interrupted it throws an InterruptedException and returns. So our application becomes responsive by using a responsive method. So we can just build upon the already existing support and write additional Thread.interrupted/Thread.currentThread().isInterrupted checks in our code.
Moreover, the cancellation methods in ExecutorService use thread interruption. As we mentioned, Future.cancel and ExecutorService.shutdownNow rely on interrupts.