Java 1.5 Tiger A Developers Notebook [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Java 1.5 Tiger A Developers Notebook [Electronic resources] - نسخه متنی

David Flanagan, Brett McLaughlin

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








10.1 Handling Uncaught Exceptions in Threads


Normally a Java thread (represented by any class that extends java.lang.Thread) stops
when its run( ) method completes. In an abnormal
case, such as when something goes wrong, the thread can terminate by
throwing an exception. This exception trickles up the thread's
ThreadGroup hierarchy, and if it gets to the root ThreadGroup, the default behavior is to print out the thread's name, exception name, exception
message, and exception stack trace.

To get around this behavior (at least in Java 1.4 and earlier), you've got
to insert your own code into the ThreadGroup hierarchy, handle the
exception, and prevent delegation back to the root ThreadGroup. While
this is certainly possible, you'll have to define your own subclass of
ThreadGroup, make sure any Threads you create are assigned to that group, and generally do a lot of coding that has very little to do with the
task at handactually handling the uncaught exception. Tiger simplifies
all this dramatically, and lets you define uncaught exception handling on
a per-Thread basis.


10.1.1 How do I do that?


The java.lang.Thread class defines a nested interface in Tiger, called Thread.UncaughtExceptionHandler. You can create your own implementation
of this interface and pass it to your target Thread's
setUncaughtExceptionHandler( ) method (also new in Tiger).
Example 10-1 is a simple Thread that does just this.


Example 10-1. Thread with uncaught exception handler


package com.oreilly.tiger.ch10;
public class BubbleSortThread extends Thread {
private int[] numbers;
public BubbleSortThread(int[] numbers) {
setName("Simple Thread");
setUncaughtExceptionHandler(
new SimpleThreadExceptionHandler( ));
this.numbers = numbers;
}
public void run( ) {
int index = numbers.length;
boolean finished = false;
while (!finished) {
index--;
finished = true;
for (int i=0; i<index; i++) {
// Create error condition
if (numbers[i+1] < 0) {
throw new IllegalArgumentException(
"Cannot pass negative numbers into this thread!");
}
if (numbers[i] > numbers[i+1]) {
// swap
int temp = numbers[i];
numbers[i] = numbers[i+1];
numbers[i+1] = temp;
finished = false;
}
}
}
}
}
class SimpleThreadExceptionHandler implements
Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
System.err.printf("%s: %s at line %d of %s%n",
t.getName( ),
e.toString( ),
e.getStackTrace( )[0].getLineNumber( ),
e.getStackTrace( )[0].getFileName( ));
}
}

NOTE

I used a bubble sort for the example, but you should know that sorts like quicksort
are much faster (and therefore much cooler).

This is a pretty normal Thread, with the exception of two items. First,
there is a rather odd condition thrown into the sorting algorithm: if an
int less than zero is in the supplied array, an IllegalArgumentException
is tossed out. Second, to handle this (rather odd) case, an implementation
of Thread.UncaughtExceptionHandler is defined, which prints out
some additional information about the problem, including a line number
and filename.

To see this in action, you can use Example 10-2, a simple test program.


Example 10-2. Testing the uncaught exception handler


package com.oreilly.tiger.ch10;
import java.io.IOException;
import java.io.PrintStream;
public class ThreadTester {
private int[] posArray = new int[] {1, 3, 6, 3, 4, 2, 5};
private int[] negArray = new int[] {-2, -8, -3, -9, -10};
public ThreadTester( ) {
}
public void testBubbleSort(PrintStream out) throws IOException {
Thread t1 = new BubbleSortThread(posArray);
t1.start( );
out.println("Testing with postive numbers...");
// Wait for the thread to complete
try {
t1.join( );
printArray(posArray, out);
} catch (InterruptedException ignored) { }
Thread t2 = new BubbleSortThread(negArray);
t2.start( );
out.println("Testing with negative numbers...");
try {
t2.join( );
printArray(negArray, out);
} catch (InterruptedException ignored) { }
}
private void printArray(int[] a, PrintStream out) throws IOException {
for (int n : a) {
out.println(n);
}
out.println( );
}
public static void main(String[] args) {
ThreadTester tester = new ThreadTester( );
try {
tester.testBubbleSort(System.out);
} catch (Exception e) {
e.printStackTrace( );
}
}
}

NOTE

Running "ant runch10" will automate this for you.

If you run this example, which generates an error when negative numbers
are supplied in negArray, you'll see the SimpleExceptionHandler in action:

NOTE

While this is a fine example, it's still a bad idea to write to the console, or even
System.err, unless you're sure where those errors are going, and that they
will be seen by some set of human eyes. A better idea would be to log these errors somewhere
useful.


[echo] Running ThreadTester...
[java] Testing with postive numbers...
[java] 1
[java] 2
[java] 3
[java] 3
[java] 4
[java] 5
[java] 6
[java] Testing with negative numbers...
[java] Simple Thread: java.lang.IllegalArgumentException: Cannot pass
negative numbers into this thread! at line 23 of
BubbleSortThread.java
[java] -2
[java] -8
[java] -3
[java] -9
[java] -10

Also, notice that the negative array (negArray) doesn't get sorted. That's because the thread threw an exception and never completed the sort.


10.1.2 What about...


...setting an UncaughtExceptionHandler for all threads? Install a default
handler: pass an implementation of Thread.UncaughtExceptionHandler
to the Thread.setDefaultUncaughtExceptionHandler( ), which is, of
course, a static method:


Thread.setUncaughtExceptionHandler(new MyDefaultHandler( ));

If a Thread has its own handler, that of course overrides the default handler. In fact, here's the exact sequence of checks that the JVM goes
through when determining how to handle an uncaught exception:

Check for a thread-specific handler to invoke, and if one exists, invoke it.

Invoke the handler of the containing ThreadGroup.

If the containing ThreadGroup (and its ancestors) have not overridden
uncaughtException( ), pass the exception up the ThreadGroup hierarchy, until the root ThreadGroup is reached.

Invoke the default handler, obtained by calling Thread.getDefaultExceptionHandler( ).



/ 131