I am in the creation of a 2d game, and when I try to stop a Thread, it suspends itself and throws a ThreadDeath error.
For some reason, this only happens in debug mode.
How can I catch this error, or prevent it?
ThreadDeath error is thrown when Thread.stop() is called. Thread.stop() is deprecated and should be avoided as it is unsafe.
Why is Thread.stop deprecated?
Because it is inherently unsafe. Stopping a thread causes it to unlock all the monitors that it has locked. (The monitors are unlocked as the ThreadDeath exception propagates up the stack.) If any of the objects previously protected by these monitors were in an inconsistent state, other threads may now view these objects in an inconsistent state. Such objects are said to be damaged. When threads operate on damaged objects, arbitrary behavior can result. This behavior may be subtle and difficult to detect, or it may be pronounced. Unlike other unchecked exceptions, ThreadDeath kills threads silently; thus, the user has no warning that his program may be corrupted. The corruption can manifest itself at any time after the actual damage occurs, even hours or days in the future.
Thread.stop() - deprecated
Best way to stop a thread is to let the Thread terminate itself naturally. For example if you have a thread that monitors your application's state using a while loop, you can use have a running field in your thread and set it to false from the main loop to allow the Thread to terminate itself gracefully.
Related
This question already has answers here:
Why do InterruptedExceptions clear a thread's interrupted status?
(4 answers)
Closed 2 years ago.
In many sources I found that Thread.interrupted() method clears interrupt status of thread, but in none of them there was explanation of the reason why this method works exactly in this way.
I still feel confused a little because of lack of understanding of this reason and lack of understating of what problem designers of java tried to solve by clearing interrupt status.
I will appreciate very much if someone could explain that and show some example.
The idea behind thread interruption is that one thread may signal another to request that it interrupt is regular processing to divert its attention to some thread-specific special action. What a thread actually does in response depends entirely on the code running in that thread.
There are two main ways in which a Thread can determine whether it has been interrupted:
Several Thread and Object methods will throw an InterruptedException if invoked in a thread whose interrupted status is set, or if a thread is interrupted while the method is executing. The interrupted status is cleared in this event, presumably because the exception is considered adequate notice of the interruption.
Code running in the thread can invoke Thread.interrupted() or Thread.currentThread().isInterrupted() to proactively test for an interrupt. The former also resets the interrupted status; the latter does not, likely because it is an instance method -- interrupts must not be lost in the event that one thread calls the isInterrupted() method of a different one.
The techniques that cause the interrupt status to be reset do so in order that the thread is able to handle subsequent interruptions. The key point here is perhaps that thread interruption is not intended to necessarily cause the interrupted thread to shut down (although that is indeed one response that a thread can make). It is a more general mechanism.
From jdoc
An interrupt is an indication to a thread that it should stop what it is doing and do something else. It's up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate
and
By convention, any method that exits by throwing an InterruptedException clears interrupt status when it does so. However, it's always possible that interrupt status will immediately be set again, by another thread invoking interrupt.
So Thread.interrupted clears the flag because it's always possible that interrupt status will immediately be set again, by another thread invoking interrupt.
Explanation https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html
I am writing a fairly large, multithreaded application, with many differing roles for threads (e.g. event processing, metrics, networking). Currently, if there is any inconsistency that cannot be handled, it will manifest itself as an exception. Since there's really no way to recover from some of them, I've been rethrowing it as a runtime exception of type ApplicationDeathException.
Any classes that need to handle shutdown would call it from a catch block for this exception, and then rethrow it in order for it to propagate up the stack).
I am considering killing off all other threads in this same manner by calling Thread#stop(Throwable) upon them. Most are fine with sudden termination, and can catch this exception should there be a need for shutdown logic. They will simply have the exception propagate up the stack, performing shutdown logic whereever needed, and eventually just killing the thread in the end. Are there any hidden dangers that I'm missing with this approach?
Thread.stop has been deprecated since it is unsafe (see the Javadoc). Instead have each thread monitor a boolean flag of some sort (see Java: How to stop thread? and likely countless other threads on SO).
In situations like this I typically implement some sort of thread pool manager that is responsible for cleanly shutting down running threads. Then when something really bad happens you only need to notify the manager to shut things down.
A quote from "Effective Java book" :
" The libraries provide the Thread.stop method, but this method was
deprecated long ago because it is inherently unsafe—its use can result
in data corruption. Do not use Thread.stop"
Anyone can tell me why ?
What if the thread you stop holds a critical lock? What if the thread has placed an object into an inconsistent state and hasn't had a chance to restore it yet? The correct way to stop a thread is with its cooperation, not by forcing it to stop from the outside.
Also, it simply doesn't make logical sense. All the threads in an application are supposed to be cooperating to achieve the same ends. If there's something that shouldn't be done, no thread should do it. There should be no reason to stop a thread -- it should only be coded to do something if that is something the application as whole needs done in the first place. If a thread needs to be stopped, it's only because the code it is running is broken -- doing things even if they should not be done. Just fix that code.
From the javadoc:
Why is Thread.stop deprecated?
Because it is inherently unsafe. Stopping a thread causes it to unlock
all the monitors that it has locked. (The monitors are unlocked as the
ThreadDeath exception propagates up the stack.) If any of the objects
previously protected by these monitors were in an inconsistent state,
other threads may now view these objects in an inconsistent state.
Such objects are said to be damaged. When threads operate on damaged
objects, arbitrary behavior can result. This behavior may be subtle
and difficult to detect, or it may be pronounced. Unlike other
unchecked exceptions, ThreadDeath kills threads silently; thus, the
user has no warning that his program may be corrupted. The corruption
can manifest itself at any time after the actual damage occurs, even
hours or days in the future.
For more information, read this:
http://docs.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html
IMHO, It's only unsafe if you use it to stop another thread. You can use it to stop the current thread without the normal issues e.g. if you need to re-throw a checked exception.
The problem with stop(), is you have no idea where in the thread you are throwing the exception or error. The only time you would consider using it is to stop third party threads which are not behaving correctly. The problem is that such threads can catch and ignore the error this triggers. If you really have unsafe or unreliable code you need to run, I suggest you use a separate process which you can kill as required.
In a nutshell, stop aborts the thread forcibly without giving it any chance to clean up. The most typical outcome is a mess.
I'm writing a server, which may be running hostile code. To prevent an attacker from throwing a thread into an infinite loop, I want to enforce a one-second execution time limit.
An InterruptedException can be caught inside an infinite loop, thus allowing an attacker to retain control of the thread. Thus Thread.interrupt() is not an acceptable solution.
My current implementation prevents hostile threads from acquiring any resources (including locks), uses Thread.stop() to terminate execution, and reverts any changes made by the thread. My main complaint is that it uses the deprecated Thread.stop() method; I don't like using deprecated code.
I'm wondering if there is a more industry-accepted solution, short of launching/killing an entirely new JVM, which would have too much overhead for my purposes.
The only way to kill a thread is to use a separate process and kill that process. Thread.stop() throws a ThreadDeath error which can be caught and ignored. i.e. catch(Throwable t) {}
For more details on what Thread.stop() actually does Does Thread.stop() really stop a Thread?
You cannot guarantee that a thread can be stopped as several blocking methods (like sockets) do not respond to interrupt().
I would suggest a very strict security manager so you can be absolutely certain that the malicious code is sandboxed. If you need to be certain then consider a special classloader which ensures that only valid operations are being done.
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.