前言:
有个批量需求,想读一张表A数据,用此表数据维护其他表数据。
因数据量可能很大,采用了单线程读表A,多线程处理其他表数据。
遇到问题
不做处理时,子线程异常是不影响主线程的。
参考了很多网上代码,如:
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100,
30L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), namedThreadFactory){
protected void afterExecute(Runnable r,Throwable t) {
super.afterExecute(r,t);
printException(r,t);
}
};
private static void printException(Runnable r,Throwable t) {
throw new RuntimeException("error");
}
或
Thread.setDefaultUncaughtExceptionHandler((t,e) -> {
throw new RuntimeException("error");
});
都无实现主线程异常。
实现
通过传参到线程池中,判断线程结果,给到线程池中。最后判断参数结果。
List<Exception> threadException = new ArrayList<>();
do {
dataList = queryClByPage(maxAcctId,1000);
// 查询无数据 等待10秒
if (CollUtil.isEmpty(dataList)) {
break;
}
maxAcctId = dataList.get(0).getId();
List<List<T>> split = CollectionUtil.split(dataList, 100));
for (List<T> batchData : split) {
// 添加任务到队列
threadPoolExecutor.execute(batchData,new DataListProcessTask(threadException));
}
}
while (1000 == dataList.size());
//不在接收新的任务
threadPoolExecutor.shutdown();
try {
// 等待所有线程执行完毕
threadPoolExecutor.awaitTermination(Long.MAX_VALUE,TimeUnit.NANOSECONDS);
log.info("任务完成,线程池关闭成功");
} catch (InterruptedException e) {
// no thing
log.info("任务完成,线程池关闭失败");
threadPoolExecutor.shutdownNow();
}
if (!threadException.isEmpty()) {
throw new RuntimeException("error");
}
线程:
public static class DataListProcessTask<T> implements Runnable {
private final List<T> batchDataList;
private List<Exception> threadException;
AppLogger log = AppLoggerFactory.getLogger(getClass());
public DataListProcessTask(List<T> batchDataList,List<Exception> threadException) {
this.batchDataList = batchDataList;
this.threadException = threadException;
}
@Override
public void run() {
// 批量处理
try {
//切数据源
function(batchDataList);
} catch (Exception e) {
this.threadException.add(e);
}
}
}