Dienstag, 17. März 2009

 

Execptions aus Threads bearbeiten

Wird innerhalb eines Trheads eine Exception geworfen, so wird der Thread abgebrochen, wenn der Thread nicht selbst die Exception behandelt. Der startende Thread bekommt die Exception nicht mit. Nehmen Sie an, Sie hätten folgende Klasse für den Thread:

/** Throws an exception 50% of the time */
class NaughtyThread implements Runnable {
public void run() {
try {
if (Math.random() > .5) {
throw new RuntimeException("badness "
+ Thread.currentThread().getName());
}
} finally {
System.out.println("ran " + Thread.currentThread().getName());
}
}
}

Würden Sie ihn einfach ganz normal starten, würde der startende Thread nichts von der Exception mitbekommen:

Thread[] threads = { new Thread(new NaughtyThread(), "bad thread 1"),
new Thread(new NaughtyThread(), "bad thread 2"),
new Thread(new NaughtyThread(), "bad thread 3"), };
for (Thread t : threads) {
t.start();
}
try {
for (Thread t : threads) {
t.join();
}
} catch (InterruptedException e) {
System.err.println("interrupted: " + e.getMessage());
}

Die Lösung ist die Verwendung eines Proxies, der die Exception auffängt und speichert und auf Wunsch einen Callback aufruft.

/**
* Catches exceptions thrown by a Runnable, so you can check/view them later
* and/or deal with them from some callback.
*/
class RunnableCatch implements Runnable {

/** Proxy we will run */
private final Runnable _proxy;

/** Callback, if any */
private final RunnableCallback _callback;

/** @guarded-by(this) */
private Exception _exception;

public RunnableCatch(final Runnable proxy) {
this(proxy, null);
}

public RunnableCatch(final Runnable proxy, RunnableCallback target) {
_proxy = proxy;
_callback = target;
}

public void run() {
try {
_proxy.run();
} catch (Exception e) {
synchronized (this) {
_exception = e;
}
if (_callback != null) {
_callback.handleException(_proxy, e);
}
}
}

/** @return any exception that occured, or NULL */
public synchronized Exception getException() {
return _exception;
}
}

Der erzeugende Thread muss im Falle eines Callbacks das Interface RunnableCallback implementieren:

/** Called when an exception occurs */
interface RunnableCallback {
void handleException(Runnable runnable, Exception exception);
}

Unser NaughtyThread kann nun auf folgende Arten aufgerufen/gestartet werden. safe1 (t1) ist der Thread ohne Callback, safe2 (t2) ist jener mit Callback:

final Runnable bad = new NaughtyThread();
// safe1 doesnt have a callback
final RunnableCatch safe1 = new RunnableCatch(bad);
// safe2 DOES have a callback
final RunnableCatch safe2 = new RunnableCatch(bad, new RunnableCallback() {
public void handleException(Runnable runnable, Exception exception) {
System.out.println("Callback handled: " + exception.getMessage());
exception.printStackTrace();
}

});
final Thread t1 = new Thread(safe1, "bad thread 1");
final Thread t2 = new Thread(safe2, "bad thread 2");
t1.start();
t2.start();
t1.join();
t2.join();
if (safe1.getException() != null) {
System.out.println("thread 1 finished with exceptions");
safe1.getException().printStackTrace();
}
System.out.println("done");


Quelle: What is the best approach to handling exceptions thrown in a separate thread? auf www.stackoverflow.com

Labels:


Kommentare:

Kommentar veröffentlichen

Abonnieren Kommentare zum Post [Atom]





<< Startseite

This page is powered by Blogger. Isn't yours?

Abonnieren Posts [Atom]