多线程中线程常常会因为抛出RuntimeException终止
考虑如下的场景:一个线程用来接收外部系统的输入(输入线程),当有输入时用调用notify()唤醒另一个输出线程,将输入内容转存到另个的系统里。
当输入线程因为RuntimeException异常退出时,输出线程就不会被唤醒。这样因为一个线程的死亡影响到其它线程的正常工作,甚至会影响到整个系统的动作。
好在java中提供了线程在抛出未捕捉异常时的处理机制UncaughtExceptionHandler
以下代码片断展示了如何在线程抛出未检查异常时重新启动一个新线程
另附上线程组的处理方法:http://www.ibm.com/developerworks/cn/java/j-jtp0924/
/**
* 多线程的管理类,多线程的初始化等
*
* @author zhaojun
*
*/
public class ThreadPool {
private static final Logger log = Logger.getLogger(ThreadPool.class);
private CrawlController controller; //controller是业务的控制器,与些例无关
private int nextSerialNumber = 1;
private ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
public ThreadPool(CrawlController controller) {
this.controller = controller;
}
public void executeThread(int size) {
for (int i = 0; i < size; i++) {
exec.execute(new ToeThread(controller, nextSerialNumber++));
}
}
public CrawlController getController() {
return this.controller;
}
/**
* 线程抛出UncaughtException时,由本类做处理 Handler会重新启动一个线程,以防止线程泄漏 使线程的数量不会减少
* 使用内部类是因为内部类可以直接使用外部类的成员exec
*
* @author zhaojun
*
*/
class ResetUncaughtExceptionHandler implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
log.info("restart thread...");
exec.execute(new ToeThread(controller, nextSerialNumber++));
log.info("new thread started...");
}
}
/**
* 对线程的一些公共初始化操作
*
* @author zhaojun
*
*/
class HandlerThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
log.info("start new thread...");
Thread t = new Thread(r);
t.setUncaughtExceptionHandler(new ResetUncaughtExceptionHandler());
log.info("thread started");
return t;
}
}
}
public static void main(String[] args) {
CrawlController controller = new CrawlController();
controller.initCrawlerWithSeeds(new String[] { "http://news.scut.edu.cn/index.action" });
ThreadPool pool = new ThreadPool(controller);
pool.executeThread(MAX_THREAD_NUMBER);
}