We examined the
start()
method to the extent of saying that
“the start()
method indirectly calls the
run()
method,” but let’s examine
exactly what happens. The start()
method does
start another thread of control, but the run()
method is not the “main” routine for this new thread.
There are other bookkeeping details that must be taken care of first.
The thread must be set up in the Java virtual machine before the
run()
method can execute. This process is
shown in Figure 1.1.
All uncaught exception conditions are handled by code outside of the
run()
method before the thread terminates. It is
this exception handling that we will examine here.
Why is this exception handler interesting to us? The default exception handler is a Java method; it can be overridden. This means that it is possible for an application to write a new default exception handler. This method looks like this:
The default exception handler is a method of the ThreadGroup class.
It is called only when an exception is thrown from the
run()
method. The thread is technically
completed when the run()
method returns, even
though the exception handler is still running in the thread.
But just what is done by the default exception handler? Practically nothing. The only task accomplished by the default exception handler is to print out the stack trace recorded by the Throwable object. This is the stack trace of the thread that threw the object in the first place. (The only exception to this is if the throwable object is a ThreadDeath object, in which case nothing happens. We’ll discuss that situation next.)
Let’s return to the banking example from Chapter 3 . We know that any uncaught exception in our ATM system is unacceptable, so we must handle every exception. But certain problems, like the ATM running out of money, may be encountered in more than one location in our algorithm. Handling the out-of -money condition in the default exception handler may be the best solution.
Let’s examine a possible implementation of our default exception handler:
public class ATMOutOfMoneyException extends RuntimeException { public ATMOutOfMoneyException() { super(); } public ATMOutOfMoneyException(String s) { super(s); } } public class ATMThreadGroup extends ThreadGroup { public ATMThreadGroup(String name) { super(name); } public void uncaughtException(Thread t, Throwable e) { if (e instanceof ATMOutOfMoneyException) { AlertAdminstrator(e); } else { super.uncaughtException(t, e); } } }
You can implement a default exception handler by overriding the
uncaughtException()
method. This requires that
you subclass the ThreadGroup class, instantiate an instance of that
subclass, and create all your threads so that they belong to that
instance. The method is passed an instance of the Thread class that
threw the object, along with the actual object that was thrown. In
our case, we are only concerned with the out-of-money condition.
Every other object that is thrown is passed to the original default
handler.