问题
- 如果线程因为未检查异常而结束,如果不采取措施就会产生线程泄露,如果线程运行的任务是重要的或者对后续的任务有,那么就可能造成更严重的后果。
- 线程池中工作者线程的结构,通过thrown和afterExecute来捕获异常,从而避免某个任务的的失败导致线程退出以及在出现异常时可以进行相应的处理。但是afterExecute方法中没有做任何处理,如果需要可以扩展ThreadPoolExecutor 。
public void run(){
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
}
- 如果希望在任务由于发生异常而失败时获得通知,并且执行一些特定于任务的恢复操作,那么可以将任务封装在能捕获异常的Runnable或Callable中,或者改写ThreadPoolExecutor的afterExecute方法。
- 扩展ThreadPoolExecutor 对异常进行处理
class ExtendedExecutor extends ThreadPoolExecutor {
* // ...
* protected void afterExecute(Runnable r, Throwable t) {
* super.afterExecute(r, t);
* if (t == null && r instanceof Future<?>) {
* try {
* Object result = ((Future<?>) r).get();
* } catch (CancellationException ce) {
* t = ce;
* } catch (ExecutionException ee) {
* t = ee.getCause();
* } catch (InterruptedException ie) {
* Thread.currentThread().interrupt(); // ignore/reset
* }
* }
* if (t != null)
* System.out.println(t);
* }
* }}</pre>
ThreadFactory定制Thread
Thread类中设置未捕获异常处理器的方法
public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
- 我们知道线程池中线程都是由ThreadFactory创建的,So 要为线程池(Executor)中的所有线程设置一个UncaughtExceptionHandler,需要为ThreadPoolExecutor的构造函数提供一个ThreadFactory,并且让其返回定制过的Thread。
//ThreadFactory接口只有一个方法,用于构建线程池中的线程
public interface ThreadFactory{
Thread newThread(Runnable r);
}
案例
为线程池中的线程定制名字(可以区别其他线程池的线程),设置自定义的UncaughtExceptionHandler,把线程未捕获的异常信息写入日志中,维护一些统计信息(包括有多少线程被创建和销毁),以及在线程被创建或者终止时把调试信息写入日志。
思考:需要实现自己ThreadFactory,并返回定义自己的MyAppThread类,为了维护线程池的统计信息,需要在MyAppThread中定义一些static变量。
自定义线程工厂
public class MyThreadFactory implements ThreadFactory {
private final String poolName;
public MyThreadFactory(String poolName) {
this.poolName = poolName;
}
public Thread newThread(Runnable runnable) {
return new MyAppThread(runnable, poolName);
}
}
- 定制Thread的基类
public class MyAppThread extends Thread {
public static final String DEFAULT_NAME = "MyAppThread";
private static volatile boolean debugLifecycle = false;
private static final AtomicInteger created = new AtomicInteger();
private static final AtomicInteger alive = new AtomicInteger();
private static final Logger log = Logger.getAnonymousLogger();
public MyAppThread(Runnable r) {
this(r, DEFAULT_NAME);
}
public MyAppThread(Runnable runnable, String name) {
super(runnable, name + "-" + created.incrementAndGet());
setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t,
Throwable e) {
log.log(Level.SEVERE,
"UNCAUGHT in thread " + t.getName(), e);
}
});
}
public void run() {
// Copy debug flag to ensure consistent value throughout.
boolean debug = debugLifecycle;
if (debug) log.log(Level.FINE, "Created " + getName());
try {
alive.incrementAndGet();
super.run();
} finally {
alive.decrementAndGet();
if (debug) log.log(Level.FINE, "Exiting " + getName());
}
}
public static int getThreadsCreated() {
return created.get();
}
public static int getThreadsAlive() {
return alive.get();
}
public static boolean getDebug() {
return debugLifecycle;
}
public static void setDebug(boolean b) {
debugLifecycle = b;
}
}