文章目录
线程池处理任务,异常处理
前言
业务开发中我们使用线程池或者线程处理任务,异常如何处理,线程并不像平时try…catch那样捕获。
异常处理
Thread中,提供了一个返回线程异常的一个方法
Thread r = new Thread(run);
r.setUncaughtExceptionHandler((t, e) -> {
System.out.println(t.getName() + " - " + " 失败 ... ");
e.printStackTrace();
System.out.println(" =================== ");
});
我们可以打印出线程运行中的异常
而在线程池中,我们如何获取?
自定义线程池时,指定线程的异常管理器
代码实例如下:
MyThreadFactory myThreadFactory = new MyThreadFactory();
ThreadPoolExecutor executorService =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(30),
myThreadFactory);
for (int i = 0; i < 20; i++) {
executorService.execute(() -> {
int n = 1 / 0;
});
}
System.out.println(" ---- main ----- ");
executorService.awaitTermination(100, TimeUnit.SECONDS);
//executorService.shutdown();
}
private static class MyThreadFactory implements ThreadFactory {
private static final AtomicInteger a = new AtomicInteger();
@Override
public Thread newThread(Runnable run) {
Thread r = new Thread(run);
r.setName("thread -" + a.getAndIncrement());
r.setUncaughtExceptionHandler((t, e) -> {
System.out.println(t.getName() + " - " + " 失败 ... ");
e.printStackTrace();
System.out.println(" =================== ");
});
return r;
}
}
此时,就可以打印出每个线程的异常
但是,有些场景,我们在使用线程池时,如果业务代码执行异常,或者没成功。
可能我们需要记录数据,或者重新操作等。需要保存一个标识等等,此时这种异常就不适合我们
由于执行的是runable 我们可以自定义一个runable模板,代码如下
//模板处理异常
ExecutorService executorService2 = Executors.newFixedThreadPool(4,new MyThreadFactory());
IntStream.rangeClosed(1, 10).boxed().forEach(x -> {
// 处理任务,返回处理状态
executorService2.execute(
new MyTask(x) {
@Override
protected void error(Throwable e) {
if (x % 3 == 0) {
System.out.println(x + " ---> 任务 error " + e.getMessage());
}
}
@Override
protected void doExecute() {
System.out.println(x + " ---> 任务 error ");
}
@Override
protected void done() {
System.out.println(x + " ---> 任务 done ");
}
@Override
protected void doInit() {
}
});
});
executorService2.shutdown();
executorService2.awaitTermination(50, TimeUnit.SECONDS);
System.out.println(" ================ ");
}
private static class MyThreadFactory implements ThreadFactory {
private static final AtomicInteger a = new AtomicInteger();
@Override
public Thread newThread(Runnable run) {
Thread r = new Thread(run);
r.setName("thread -" + a.getAndIncrement());
r.setUncaughtExceptionHandler((t, e) -> {
System.out.println(t.getName() + " - " + " 失败 ... ");
e.printStackTrace();
System.out.println(" =================== ");
});
return r;
}
}
private abstract static class MyTask implements Runnable {
private final int no;
protected MyTask(int no) {
this.no = no;
}
@Override
public void run() {
//System.out.println(" ======= MyTask run ========= ");
doInit();
try {
doExecute();
done();
}catch (Throwable e){
error(e);
}
}
protected abstract void error(Throwable e);
protected abstract void doExecute();
protected abstract void done();
protected abstract void doInit();
}
可以看到通过这种模板方法可以在任务里面处理异常
1 —> 任务 error
2 —> 任务 error
1 —> 任务 done
2 —> 任务 done
3 —> 任务 error
3 —> 任务 done
4 —> 任务 error
4 —> 任务 done
5 —> 任务 error
5 —> 任务 done
6 —> 任务 error
9 —> 任务 error
8 —> 任务 error
8 —> 任务 done
7 —> 任务 error
10 —> 任务 error
10 —> 任务 done
9 —> 任务 done
6 —> 任务 done
7 —> 任务 done
================
其他知识点
Java 多线程基础
深入理解aqs
ReentrantLock用法详解
深入理解信号量Semaphore
深入理解并发三大特性
并发编程之深入理解CAS
深入理解CountDownLatch
Java 线程池