I would like to shutdown a thread gracefully. However, once the shutdown is initiated the thread should perform some shutdown operation after ending usual operation.
Both threads use sleeps and/or wait and handle InterruptedException, they also work on tasks in a loop taking only a few milliseconds. So that I expected the while loop to end because Thread.currentThread().isInterrupted() becomes "true".
The problem is that with my code sometimes I get the log "SHUTDOWN" and sometimes not. Also I get "INTERRUPTED" only sometimes, which I understand of course. With another similar thread I never get the "SHUTDOWN".
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(new Test());
Thread.sleep(10000);
executor.shutdown();
try {
if(this.executor.awaitTermination(60, TimeUnit.SECONDS)) {
this.loggerFactory.getLogger(this.getClass()).info("CLOSED (GRACEFULLY)!");
} else {
this.executor.shutdownNow();
this.loggerFactory.getLogger(this.getClass()).info("CLOSED (IMMEDIATELY)!");
}
} catch(InterruptedException e) {
this.executor.shutdownNow();
this.loggerFactory.getLogger(this.getClass()).info("CLOSED (IMMEDIATELY)!");
}
class Test implements Runnable {
private volatile boolean isRunning = true;
#Override
public void run() {
try {
while(!Thread.currentThread().isInterrupted()) {
while(!this.isRunning) {
synchronized(this) {
this.wait();
}
}
// DO SOMETHING LASTING A FEW MILLISECONDS
Thread.sleep(500);
}
} catch(InterruptedException e) {
this.loggerFactory.getLogger(this.getClass()).info("INTERRUPTED!");
}
this.loggerFactory.getLogger(this.getClass()).info("SHUTDOWN!");
// DO SOME SHUTDOWN OPERATION
}
}
EDIT:
After some commentary by OP, an entirely different and much superior solution seems to be available:
Use hooks!
Java has a system to 'install' a shutdown hook. These are called when the VM shuts down... sometimes. If you get SIGTERMed (kill -9) or someone trips over a powercable, or linux kills your process due to excessive memory use, or the kernel dumps, or your VM hard crashes (for example, a core dump in native code), or the device loses power, they don't get called, of course.
But, if someone in the process runs System.exit(), or all non-daemon threads are done, or someone hits CTRL+C or sends SIGKILL (kill, not kill -9) to your process, they get run first, and only when they all finish does the java process actually end.
That sounds like a vastly superior solution here. Your shutdown hook should:
acquire the lock on some private AtomicBoolean.
set the boolean to false (the boolean indicates: May I query this sensor?)
release the lock.
reset the sensor.
return.
And all your normal operation code that reads that sensor should:
acquire a lock on the boolean.
if false, throw or otherwise abort.
perform the sensor read operation.
release the lock.
Nothing should ever touch that sensor without holding the lock (failure to do this would imply maybe messing with that sensor after you've already reset it, which would be bad).
original answer:
I would like to shutdown a thread gracefully.
Why? 'gracefully' is a very nice sounding word, but once you dig into what it means, it's just nasty things. It's a word that means: "That will cause my software to fail, possibly persistently (as in, won't start anymore without cleaning up stuff), if someone trips over a powercable or my app hard-crashes".
A much better design is to have a thread that doesn't need to be shut down. Just pull the plug on it, and all is well.
For example, old filesystems (MS-DOS and early windows age) required graceful shutdowns; failure to do so would lead to persistent issues - the system wouldn't boot at all, you bricked the box. They then had mitigation systems in place (chkdsk systems), but modern OSes are much better. Their filesystem handling setup mostly doesn't care about being 'gracefully' shut down. Just pull the plug on em, they'll be fine, that's what journals do.
So that I expected the while loop to end because Thread.currentThread().isInterrupted() becomes "true".
That's not how you're supposed to use that API.
Here's the basic gist of what the interrupted API does:
Any thread can 'raise the interrupt flag' on any other (someThread.interrupt()).
raising the flag doesn't do anything other than raise the flag, unless a method explicitly decides to look at it.
The method Thread.interrupted() is how you're supposed to read the flag out in order to act upon it, __and not Thread.currentThread().isInterrupted(). The former will check the flag and clear it. The latter merely checks the flag.
Some java methods are specced to respond to the flag being up. You recognize these methods because they throws InterruptedException. There may be more methods; for example, on most OSes, interrupting a thread currently waiting for more bytes to flow in from the network (they are blocked on a read() call on an InputStream obtained from socket.getInputStream()) WILL cause that read call to fail (with an IOException, not an InterruptedException, because read() isn't specced to throw InterruptedEx), but that's no guarantee; on some OSes, it won't, and you can't interrupted that.
The general policy is that the moment you handle an interrupted flag, you lower the flag, and java code does just that: If a method throws InterruptedEx, the flag will be cleared.
Java does not define what you should do if interrupted. Threads don't get magically interrupted; for example, when your VM shuts down (someone hits CTRL+C), that doesn't interrupt any threads whatsoever. Java will just 'pull the plug' on all threads. That's because this is better (see above). Therefore, if a thread is interrupted, that's because you wrote thread.interrupt() someplace, therefore, you decide what it means. Maybe it means 're-read a config file and restart the server listening process'. Maybe it means 'stop calculating chess moves and perform the best move found so far'. Maybe it means 'recheck for a condition'. Maybe it means 'end the thread entirely'. It's up to you. There is no standard.
Note that the various methods specced to respond to interrupt flags (such as wait(): It throws InterruptedException) all share this property: If you call them while the flag is up, they will instantly return by throwing InterruptedException, they never even begin waiting.
So, for your code, given that you wait() already, just make that while(true) and rely on the InterruptedEx.
Related
I've written a custom UncaughtExceptionHandler that should print the exception to the console and shut down the application with a custom exit code.
The class looks like this:
public class FatalUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
#Override
public void uncaughtException(final Thread t, final Throwable e) {
System.out.println("Handled exception in " + t.getName() + ":");
e.printStackTrace();
System.exit(ExitCodes.UNKNOWN_EXCEPTION);
}
}
I set the UncaughtExceptionHandler in my Main.class like this:
Thread.setDefaultUncaughtExceptionHandler(new FatalUncaughtExceptionHandler());
Then I generate and start 4 threads.
In one of the running threads I purposely generate a NumberFormatException using Integer.valueOf("Test") in order to test my Handler. This works fine; Here's the output:
Handled exception in WatchdogThread:
java.lang.NumberFormatException: For input string: "Test"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.valueOf(Integer.java:766)
at com.csg.gfms.gms.ctmgate.runnable.WatchdogThread.run(WatchdogThread.java:43)
Now I have a problem. For some reason the thread in which the exception was thrown is not being shutdown by the System.exit() command. Apparently my ShutdownHook has a lock on it. (As seen in the output of jvisualvm):
"WatchdogThread" #38 prio=5 os_prio=0 tid=0x000000001efa3800 nid=0xd40 in Object.wait() [0x0000000021a5e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076e30a7c0> (a com.csg.gfms.gms.ctmgate.runnable.CTMShutdownHook)
at java.lang.Thread.join(Thread.java:1252)
- locked <0x000000076e30a7c0> (a com.csg.gfms.gms.ctmgate.runnable.CTMShutdownHook)
at java.lang.Thread.join(Thread.java:1326)
at java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:107)
at java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:46)
at java.lang.Shutdown.runHooks(Shutdown.java:123)
at java.lang.Shutdown.sequence(Shutdown.java:167)
at java.lang.Shutdown.exit(Shutdown.java:212)
- locked <0x00000006c9605b00> (a java.lang.Class for java.lang.Shutdown)
at java.lang.Runtime.exit(Runtime.java:109)
at java.lang.System.exit(System.java:971)
at com.csg.gfms.gms.ctmgate.handlers.FatalUncaughtExceptionHandler.uncaughtException(FatalUncaughtExceptionHandler.java:13)
at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1057)
at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
at java.lang.Thread.dispatchUncaughtException(Thread.java:1959
Even IntelliJ tells me that the System.exit command will fail. It displays a little badge next to it saying "Method will fail" when debugging my UncaughtExceptionHandler.
This leads me to my question:
Is it not allowed to call System.exit() from an UncaughtExceptionHandler?
Is the shutdown hook initiated twice in my case?
What could be the reason for the lock on the shutdown hook?
See that com.csg.gfms stuff in the trace?
It's not java; it's you. That's your code that's blocking in another shutdown hook; one that is calling Thread.join.
Generally when running into such weirdness, if it is at all possible to make a stand-alone super simple test case, then you should do so. I have done this for you:
class Test {
public static void main(String[] args) throws Exception {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
System.out.println("EXITING");
System.exit(1);
}
});
for (int i = 0; i < 10; i++) {
Thread t = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(1000L);
} catch (Exception ignore) {}
throw new RuntimeException();
}
});
t.start();
}
Thread.sleep(2000L);
System.out.println("Still alive?");
}
}
When I run this, I get an arbitrary number of EXITING prints (2 to 3, it's dependent on how many cores are simultaneously working on these threads), and then the VM hard-exits. Still alive? is never printed, no locking occurs, the VM actually exits.
Thus proving that calling System.exit() from within the uncaught exception handler is not an issue.
The shutdown hook is not invoked twice; the shutdown hook is invoked due to you invoking System.exit, not because we got to the uncaught exception handler. But, if you're worried about this, hey, it's your app, print something in your shutdown hooks to be sure.
The lock issue is not on the shutdown hook. You can register any amount of shutdown hooks. It's in a shutdown hook. Specifically: somebody registered an instance of com.csg.gfms.gms.ctmgate.runnable.CTMShutdownHook, that code is joining some thread, and that thread is not shutting down, thus that hook never exits, thus System.exit is not exiting the VM. The solution is to fix CTMShutdownHook, which is broken.
Joining a thread in a shutdown hook is... well, I'll just say it bluntly: Stupid. I don't quite know what this is trying to accomplish, but the only thing I can think of is forced adherence to a bad standard. Therefore, I can foresee that you, or the author of CTMShutdownHook, first needs some introspective on how to deal with JVM shutdowns, so that they understand that the idea underlying their implementation is fundamentally misguided and needs to be rethought.
I will do that here.
There is this mindset that to 'properly' shut down a VM, one should never invoke System.exit, one should instead carefully tell all running threads to stop, and one should carefully manage the daemon flag on all threads, so that the VM will end up shutting down on its own volition because all still alive threads have the daemon flag set. The argument being that this gives each thread the chance to 'shut down nicely'.
This is bad code style.
Your app will just shut down if someone hits CTRL+C or otherwise asks the VM to exit, this will not result in a nice 'ask all threads to clean up and stop' process. In fact, your app gets zero opportunity to clean up anything if someone trips over a powercable, the computer hard-crashes, or someone terminates the app.
This leads to the following rules:
Any code that is written so that it breaks if not shut down nicely (e.g. you keep some state in memory, and upon being asked to quit, you save this state to disk; it is quite a serious bug if this state is just forgotten) is bad code. It is always possible to write code so that recovery is possible. Even extreme cases, such as filesystems, can (these days) handle just pulling the cord using e.g. journalling technology.
If you want to at least 'be nice' and try to save state or otherwise cleanup, do not wait for someone to tell your thread to 'exit nicely'. Just register a shutdown handler which does the cleanup, and assume your main thread loop will just straight up abort at some arbitrary point without any further notification. This is not actually hard to write.
Said differently: Don't ever assume your thread will be told to clean up after itself. Assume that usually any registered shutdownhandlers are invoked, but don't rely on them entirely, as in rare scenarios (power pulse, kill -9, VM core crash, memory issues, someone runs this in an IDE and just kills it, which is usually a hard-kill, the list is long) those don't run either.
By adding a shutdownhook that 'joins' a thread (joining = pause this thread until that thread exits), you've created a very silly scenario where of the 3 different ways to shut an app down:
Someone trips over a powercable or kill -9s your app: Everything dies on the spot, no cleanup possible.
CTRL+C is hit or someone calls System.exit or normal SIGKILLs your app: Everything dies on the spot, but all shutdown hooks are invoked.
(Misguided) Within the app some process starts trying to get all non-daemon threads to return, and they will presumably be doing their cleanup internally.
What 'join this thread in a shutdown hook' does is effectively downgrade that second form to the (bad) third form.
With that context, you can now fix the broken code in CTMShutdownHook, or talk to the developer of that hook and explain to them that the elegant-sounding idea of allowing all running threads to shut down nicely is in fact bad.
Then as a more general point of principle, shutdown hooks should block as little as possible and should definitely not wait for other threads to act.
Consider this scenario:
I want to make several web service calls consecutively. I am only allowed to make a call every 10 seconds. I have something like this:
while(true) //we will break inside the loop eventually
{
//...
try {
Thread.sleep(10000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
//make web service call here
//...
}
As you can see, This will (hopefully) make a call approximately every 10 seconds. But my concern is that while Thread.sleep() is executing, I will get interrupted before 10 seconds and I will subsequently make a web service call that will get ignored.
This is not a multithreaded application so it runs on its own JVM. This is the only thread I am not calling interrupt() on this thread from anywhere, but I am not sure if I will run into trouble with my host machine's thread scheduler or anything.
Accuracy of timekeeping is not of great importance. I especially don't care if the 10 seconds turns into 15 seconds. But if somehow Thread.Sleep throws too soon I will be in trouble.
Is this the proper way of implementing this behaviour?
To clarify:
1- this is NOT a multi-threaded program
2- I do NOT want to do a exact times, the timing can be inaccurate as long as an unexpected exception does not get me out of the try block prematurely
I am not sure if I will run into trouble with my host machine's thread scheduler
No, the runtime will not interrupt an application thread for any reason. Only other code in your application (or code that you drag in with some framework that you choose) will interrupt threads.
Every task should specify an interruption policy: what will happen if the thread is interrupted? An application should never interrupt a thread without understanding its interrupt policy and being prepared to deal with the consequences.
So, define the interrupt policy for your thread. In your application, it is something you don't expect to happen, and if someone adds code to your application that calls interrupt() on your thread, they introduced a bug. Basically, your policy is that interruption isn't allowed. So, throwing a some unchecked exception, like IllegalStateException is a valid response.
Is this the proper way of implementing this behaviour?
No, it's not. When you are interrupted, you should signal callers that you were interrupted. This should be done by letting an InterruptedException propagate back to the caller (or a application-defined exception with similar meaning), or by restoring the interrupt status on the current thread. Suppose your interruption policy permits interruption, by terminating the loop prematurely. You should still restore the interrupt status:
while(true) {
...
try {
Thread.sleep(10000);
} catch(InterruptedException abort) {
Thread.currentThread().interrupt();
break;
}
/* Make web service call here... */
}
No, it is not guaranteed to wait for at least 10 seconds. The whole point of the sleep method throwing the checked exception InterruptedException is the possible need to end the sleep before the 10 seconds are up, by interrupting the thread.
You are wrong to focus on your program being "single threaded". In practice there is no such thing: the JVM and the JRE are permitted (and in fact do) run additional threads. The Thread.sleep() API says that the method throws InterruptedException if the sleeping thread is interrupted by another thread; it does not specify that only "user" threads are permitted to interrupt the sleeping thread.
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.
The official Sun Oracle stance on Thread.stop() is that it should not be used. Among other arguments, they write:
It should be noted that in all situations where a waiting thread doesn't respond to Thread.interrupt, it wouldn't respond to Thread.stop either.
But I do not understand that. If a thread is busy actively working on something (not just waiting or blocking on an external resource) and doesn't explicitly check the interrupt flag, wouldn't Thread.interrupt() do nothing while Thread.stop() will still work (throw ThreadDeath)?
But I do not understand that. If a thread is busy actively working on something (not just waiting or blocking on an external resource) and doesn't explicitly check the interrupt flag, wouldn't Thread.interrupt() do nothing while Thread.stop() will still work (throw ThreadDeath)?
I think you misunderstand the quoted text. It refers to a thread that is waiting, not a thread that is running. Specifically, it is referring to cases like the following:
When the thread is blocked in an I/O call, low-level JVM implementation issues prevent it responding to either a stop or an interrupt.
A thread that doesn't want to be stopped can catch ThreadDeath, and this is analogous to a thread that doesn't want to be interrupted simply ignoring the flag.
Thread.stop is not an issue about being good or bad coding with regard to being able to bail out threads.
You should not use it unless as a very last resort. It is possible to do your code and expect Thread.stop() to occur but in that case interrupt() will possible do just as fine.
The issue that stop() won't work where interrupt() doesn't (i.e. blocked on some native stuff): both stop and ineterrupt would use the same native signals to carry the call.
On POSIX, if SIGUSR2 (for instance) doesn't help the native code to bail out, it won't help either of interrupt/stop.
You can think of interrupt vs stop like that: both may use OS signals. The OS signals may not be honored by the native code. However, if they are: stop() also puts a Throwable on the stack that will be propagated in the java code. On the contrary interrupt only sets a flag.
The throwable, however, may pop-up in virtually any statement, so some invariants may fail to be properly handled.
Possibly, it's partly fixable via Thread.uncaughtExceptionHandler by throwing away large states, rolling back transactions, etc... Again: not advisable.
The main reason, as far as I understand, is that the ThreadDeath exception may be thrown anywhere, whereas the interupt flag has to be checked explicitly.
Consider this code running in a thread:
public void sellItem(Store s) {
synchronized (s) {
if (s.itemsAvailable > 0) {
s.itemsAvailable--;
s.itemsSold++;
}
}
}
If a ThreadDeath is thrown after s.itemsAvailable--, the Store object is left in an inconsistent state. On the other hand, this code is safe:
public void sellLoop(Store s) {
while (!Thread.interrupted())
sellItem(s);
}
Source: http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#stop%28%29
They say that Thread.stop() would not work because (I guess) the throwable can be caught and ignored.
if the JVM is too busy to interrupt the thread, it's also too busy to kill it.
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.