ThreadPoolExecutor线程池解析
ThreadPoolExecutor线程池解析
一、ThreadPoolExecutor常见参数
jdk中Executors提供了几种常用的线程池,底层都是ThreadPoolExecutor。
public ThreadPoolExecutor(int corePoolSize,//核心线程数
int maximumPoolSize,// 最大线程数
long keepAliveTime,//非核心线程空闲存活时间
TimeUnit unit,// 时间单位
BlockingQueue<Runnable> workQueue,// 工作队列
ThreadFactory threadFactory,//线程工厂
RejectedExecutionHandler handler //线程池拒绝策略
) {}
核心线程是正式工,最大线程数中除去这部分都是临时工(工作队列满了才用到),有活就干,没活就歇着,歇的时间长了就被干掉,工作队列中就是排好的活,当正式工和零时工都在干活,排期也排满了,就执行拒绝策略。
二、ThreadPoolExecutor线程池中异常捕获处理方案
submit可以提交Callable和Runnable两种类型的task,execute只能执行Runnable.
submit在执行task的时候,会将其封装成RunnableFuture,这样使得有返回结果,可以通过get获取返回值,但是在异常处理方面和execute会有区分。
1、submit、execute执行task出现异常
使用ThreadPoolExecutor提交任务时,submit、execute两种方式都可,但submit只是提交了任务,即使任务中出现异常,也不会有任何提示。
@org.junit.jupiter.api.Test
void testF1() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
executor.submit(new Task());
executor.execute(new Task());
System.out.println("over");
}
class Task implements Runnable {
@Override
public void run() {
int i = 1/0;
}
}
结果 Exception in thread "pool-1-thread-2" java.lang.ArithmeticException: / by zero
submit提交任务都不会捕捉异常,在get才会得到异常。
Future<?> future =executor.submit(new Task());
future.get();
此时会抛出异常
2、异常处理
2.1 在task中try...catch
@org.junit.jupiter.api.Test
void testF1() throws ExecutionException, InterruptedException {
List<String> list = Arrays.asList("hello", "world");
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
executor.submit(new Task());
executor.execute(new Task());
System.out.println("over");
}
class Task implements Runnable {
@Override
public void run() {
try {
int i = 1/0;
}catch (Exception e){
System.out.println("异常");
}
}
}
task会进入catch中
over 异常 异常
2.2使用Thread.setDefaultUncaughtExceptionHandler方法自定义ThreadFactory
通过自定义ThreadFactory中生产的Thread,线程池在execute方法中出发异常会执行setDefaultUncaughtExceptionHandler中定义的内容,同样对submit无效。
//1.实现一个自己的线程池工厂
ThreadFactory factory = (Runnable r) -> {
//创建一个线程
Thread t = new Thread(r);
//给创建的线程设置UncaughtExceptionHandler对象 里面实现异常的默认逻辑
t.setDefaultUncaughtExceptionHandler((Thread thread1, Throwable e) -> {
System.out.println("线程工厂设置的exceptionHandler" + e.getMessage());
});
return t;
};
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),factory);
executor.execute(new Task());// 线程工厂设置的exceptionHandler
executor.submit(new Task()); // 无反应
2.3 重写ThreadPoolExecutor的afterExecute方法
通过重写ThreadPoolExecutor的afterExecute方法,可以处理submit和execute异常,但是submit提交的需要加一步判断。
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>()) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
//默认捕获execute中的异常
if (t != null) {
System.out.println("afterExecute里面获取到excute提交的异常信息,处理异常" + t.getMessage());
}
//如果r的实际类型是FutureTask 那么是submit提交的,所以可以在里面get到异常
if (r instanceof FutureTask) {
try {
Future<?> future = (Future<?>) r;
//get获取异常
future.get();
} catch (Exception e) {
System.out.println("afterExecute里面获取到submit提交的异常信息,处理异常" + e);
}
}
}
};
executor.execute(new Task());//处理异常
executor.submit(new Task());//处理异常