ThreadPoolExecutor线程池解析

ThreadPoolExecutor线程池解析

一、ThreadPoolExecutor常见参数

jdk中Executors提供了几种常用的线程池,底层都是ThreadPoolExecutor。

    public ThreadPoolExecutor(int corePoolSize,//核心线程数
                              int maximumPoolSize,// 最大线程数
                              long keepAliveTime,//非核心线程空闲存活时间
                              TimeUnit unit,// 时间单位
                              BlockingQueue<Runnable> workQueue,// 工作队列
                              ThreadFactory threadFactory,//线程工厂
                              RejectedExecutionHandler handler //线程池拒绝策略
) {}

核心线程是正式工,最大线程数中除去这部分都是临时工(工作队列满了才用到),有活就干,没活就歇着,歇的时间长了就被干掉,工作队列中就是排好的活,当正式工和零时工都在干活,排期也排满了,就执行拒绝策略。

Pool

二、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());//处理异常
posted @ 2024-04-11 11:13  cgl_dong  阅读(11)  评论(0编辑  收藏  举报