Class ThreadDeath Error in Java
ThreadDeath Error in Java is thrown from an application when the stop() a deprecated method of Thread with zero arguments is called for a thread. It is used to kill the thread.
The victim thread throws this error to indicate that it has been killed without providing any reason. It also indicates that the victim thread should terminate.
In general, any program must not catch instances of ThreadDeathError class once it cleans up after terminating asynchronously.
This is a very unusual way to terminate a thread without printing any error message or giving justification to the interpreter to exit. This type of Error should not be caught.
If we catch this type of Error to do some cleanup activity for the thread, we must re-throw the Error to terminate the thread(to allow the thread die silently).
If ThreadDeath is not caught, the top-level error handler of java does not point any error message. ThreadDeathError typically needs to stop a thread thus it is a very special class of java.
Normally we should not catch ThreadDeath object is a try statement. If at all, we need to catch the ThreadDeath objects to detect that a Thread is about to die, the try statement that catches the ThreadDeath objects should rethrow then.
When an object (ThreadDeath or otherwise) is thrown out of a run() method for the thread, the uncaughtException() method of the ThreadGroup for that thread is called.
If an object is thrown from a class or application is an instance of the ThreadDeath class, the thread eventually dies and the thrown object is ignored.
Otherwise, if the thrown object is of any other class, UncaughtException() calls the thrown object’s printStackTrace() method, the thread dies and the thrown object is ignored.
In both cases, if there are other non-daemon threads running in the system, the current program continues to run.
The ThreadDeath Class hierarchy is as follows
java.lang.Object
|+-java.lang.Throwable
|+-java.lang.Error
|+-java.lang.ThreadDeath
ThreadDeathError implements the Serializable interface.
Namespace:- Java.lang.
ThreadDeath in Android Context
ThreadDeath error is also available android under the assembly of Mono.Android.dll
The class structure of ThreadDeath is given as:
public class java.lang.ThreadDeath extends java.lang.Error{
//constructor
public ThreadDeath();
//constructs an empty ThreadDeath object that is an object with no message specified.
}
The class ThreadDeath error also inherits methods from class Object and Throwable.
From Object class | From Throwable class |
---|---|
clone() | fillInStackTrace() |
getClass() | getMessage() |
notify() | printStackTrace() |
wait() | printStackTrace(PrintWriter) |
wait(long, int) | getLocalizedMessage() |
wait(long) | printStackTrace(PrintStream) |
equals(Object) | addSuppressed() |
finalize() | getCause() |
hashCode() | getStackTrace() |
notifyAll() | getSuppressed() |
initCause() | |
toString() | |
setStackTrace() |
A Code snippet to generate ThreadDeathError in Java
Thread myThread = new Thread();
@override
public void run(){
try{
System.out.pintln(“My Thread started”);
Thread.sleep(1000);
System.out.println(“My thread ended”);
}
catch(InterruptedException e){
System.out.println(“My thread is interrupted”);
}
catch(Error e){
System.out.println(e);
Throw e;
}
myThread.start();
myThread.join();
myThread.stop();
The output of the code:
My thread Started.
java.lang.ThreadDeath.
Why Thread.stop is potentially unsafe to work?
As coders do not have any control on threads, when it starts and stops, so when coders issue a Thread.stop() command, it makes the objects or shared resources in an inconsistent state. It may work 9 out of 10 times but fail in the last instance. Incase coder catch this error and does not rethrow, the thread will not die(stop).
How to stop a thread by throwing an object in java?
As soon as the run() method is completed, the thread itself clean it up the resources. Now run() can be completed in two different ways:-
- Get completed on its own.
- By throwing an object.
By default run() method throws an exception along with error message and stack trace, but for ThreadDeathError, uncaughtException is thrown.
It is possible to catch any throwable object like ThreadDeathError – it is very much possible to catch but java does not permit this. Or on the other hand, it is not advisable in java. Except for UnSatisfiedLinkError.
Class invariants are preserved by Threads if programmers allow them to exit normally. In case the coders think that the thread’s job is completed, then they try to cancel, stop a thread abruptly.
In case of coders try to stop a thread by Thread.stop() method, the thread releases all locks and exposes the object. The object may have acquired these locks to protect itself.
In the case of ThreadDeath exception, the finally block may try to attempt to repair the inconsistent object.
Interestingly, if coder prints stack trace to ThreadDead, it prints which thread has actually created this, not which thread stops it. A subclass of ThreadDeath by default will not print details as well.
How to resolve ThreadDeathError?
Using Security Policy update
Remove the stop Thread from java.lang.RuntimePermission security policy. Thus no coders can invoke Thread.stop() method. But this method has several issues too. They are as follows:
- Custom-developed codes, third party libraries may depend on Throw.stop() method.
- The security policy may not be able to capture/handle other security exceptions.
- It is not a good practice to terminate JVM with untrusted and non-compliant code like deprecated Thread.stop().
Use of Volatile flag
Use of a volatile flag as a complainant solution. The shutdown() method can set a flag to true. The thread’s run() method can poll this flag (say isDone) and terminates the thread.
Use Thread.interrupt() method
Use Thread.interrupt() method to terminate a thread. Thread.interrupt() method can set a flag (status) and Thread.interrupted() method can poll and terminate a thread. A Thread can be interrupted with the guidance of interruption policy.
Use the isRunning flag
Use the isRunning flag if threads are operating on sockets. Rethrowing errors acts like an unchecked exception, it just hides these and does not provide the real cause.
ThreadDeath error if not caught do not point any error logs. ThreadGroup.uncaughtException() actually ignore this, by default. So we need to overrides this behaviour by changing Throw.SetDefaultUncaughtExceptionHandler() method.
Make the thread interruptable
The best alternative to make it interruptable:-
If(thread.interrupt()){ throw new InterruptedException(); }
So in case, the coder is trying to stop an interruptable thread can actually call Thread.interrupt() or can call Future.cancel(true). These two methods can stop a thread in a safe place without leaving objects or resources into an inconsistent state.
What are the risks of Stopping a thread?
When coders force a thread to stop, it can produce an inconsistent status for object resulting severs resource leak. This is due to the non-performance of cleanup activities.
As per JDK-7 docs – Thread.stop() method generates an exception and the target thread is not prepared to handle.
Conclusion
Throwing a ThreadDeathError to stop a thread is an unhealthy and bad practice. Coders have to use permissible ways to stop a thread.
Currently, Thread.stop() method is deprecated for a valid and great cause. But there are times when developers do not have other options.