ThreadPoolExecutor线程池解析
一、ThreadPoolExecutor常见参数
jdk中Executors提供了几种常用的线程池,底层都是ThreadPoolExecutor。
public ThreadPoolExecutor(int corePoolSize,//核心线程数int maximumPoolSize,// 最大线程数long keepAliveTime,//非核心线程空闲存活时间TimeUnit unit,// 时间单位BlockingQueue<Runnable> workQueue,// 工作队列ThreadFactory threadFactory,//线程工厂RejectedExecutionHandler handler //线程池拒绝策略
) {}
核心线程是正式工,最大线程数中除去这部分都是临时工(工作队列满了才用到),有活就干,没活就歇着,歇的时间长了就被干掉,工作队列中就是排好的活,当正式工和零时工都在干活,排期也排满了,就执行拒绝策略。
图片转载自https://blog.csdn.net/Anenan/article/details/115603481
二、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 {@Overridepublic 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.Testvoid 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 {@Overridepublic 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<>()) {@Overrideprotected 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());//处理异常