ThreadPoolExecutor参数详解和优化建议

2020-10-28  本文已影响0人  山间草夫
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            5,
            10,
            20,
            TimeUnit.MINUTES,
            new SynchronousQueue<Runnable>(),
            new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    return new Thread();
                }
            },
            new RejectedExecutionHandler() {
                @Override
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

                }
            });

按照上面参数顺序讲解

  1. \color{#FF0000}{corePoolSize 核心线程池数量 }
  1. \color{#FF0000}{maxPoolSize最大线程池数量}
  1. \color{#FF0000}{keepAliveTime 线程空闲时间}
  1. \color{#FF0000}{BlockingQueue 阻塞队列}

6 . \color{#FF0000}{ThreadFactory 线程工厂}

  1. \color{#FF0000}{rejectedExecutionHandler 拒绝策略}

线程执行的一些流程

  1. 如果当前线程池中的线程数目 小于 < corePoolSize 。则对于每个新任务,都会创建一个线程去执行这个任务(即使core线程中也有空闲线程, 也会新创建线程会执行)。
  2. 如果当前线程池中的线程数目 大于等于 >= corePoolSize 。
    对于每个新任务,会将其添加到任务队列中。若添加成功,则任务由空闲的线程主动将其从队列中移除后执行。若添加失败(任务队列已满),则尝试创建新的线程执行。
  3. 若当前线程池中的线程数目到达 maximumPoolSize ,则对于新任务采取拒绝策略。
  4. 如果线程池中的数量大于 corePoolSize 时,如果某个线程空闲时间超过 keepAliveTime ,线程会被终止,直到线程池中的线程数目不超过 corePoolSize 。
  5. 如果为核心线程池中的线程设置存活时间,则当核心线程池中的线程空闲时间超过 keepAliveTime ,则该线程也会被终止
  6. 如果核心线程数已经达到, 如果没有队列没有满的话, 是不会创建新的线程. 有时候取决你使用什么队列. 比如使用 ArrayBlockingQueue(10), 当核心线程已经创建完成, 只有当队列满了之后才会继续创建新的线程. 如果你使用的是SynchronousQueue, 内部只能一个的队列,那么只有队列直接创建core线程到maxpoolSize 之间的线程

线程池性能优化建议

  1. 建议使用 prestartAllCoreThread 或者prestartAllCoreThread 初始化核心线程
  2. 考虑 allowCoreThreadTimeOut 允许核心线程能够回收节约机器的使用.
  3. 拒绝策略可以将任务, 提交给 second 线程池处理.
  4. 自定义ThreadFactory ,标识线程, 方便排查线程的使用情况

关于线程异常是否处理的问题:

  1. execute : 如果不手动捕获一场, 线程池只能重新创建新的异常来填补空白,重新创建线程这是有代价的
  2. submit: 因为能够调用 future.get(). 所以有异常也会捕获, 不会造成线程终止.
// 证明execute 的异常
    @Test
    public void test1() throws InterruptedException {
        Thread.setDefaultUncaughtExceptionHandler((Thread t, Throwable e) -> {
            log.warn("Exception in thread {}", t, e);
        });
        String prefix = "test";
        ExecutorService threadPool = Executors.newFixedThreadPool(1, new ThreadUtil.ThreadFactoryImpl(prefix));
        IntStream.rangeClosed(1, 10).forEach(i -> threadPool.execute(() -> {
            if (i == 5) {
                throw new RuntimeException("error");
            }
            log.info("I'm done : {}", i);
            System.out.println(Thread.currentThread().getName() + " I'm done : " + i);
            if (i < 5) {
                Assert.assertEquals(prefix + "1",  Thread.currentThread().getName());
            } else {
                Assert.assertEquals(prefix + "2", Thread.currentThread().getName());
            }

        }));
        threadPool.shutdown();
        threadPool.awaitTermination(1, TimeUnit.HOURS);
        // 本来是通过test 1 线程执行的, 后面出现异常 确是test2 执行的, 说明x线程已经终止2, 并且重新创建线程
    }
// 线程名称没有变, 说明已经帮你捕获异常.
String prefix = "test";
        ExecutorService threadPool = Executors.newFixedThreadPool(1, new ThreadUtil.ThreadFactoryImpl(prefix));
        List<Future> futures = new ArrayList<>();
        IntStream.rangeClosed(1, 10).forEach(i -> futures.add(threadPool.submit(() -> {
            if (i == 5) {
                throw new RuntimeException("error");
            }
            log.info("I'm done : {}", i);
//            if (i < 5) Assert.assertEquals(prefix + "1", Thread.currentThread().getName());
//            else Assert.assertEquals(prefix + "2", Thread.currentThread().getName());
        })));

        for (Future future : futures) {
            try {
                future.get();
            } catch (ExecutionException e) {
                log.warn("future ExecutionException", e);
            }
        }
        threadPool.shutdown();
        threadPool.awaitTermination(1, TimeUnit.HOURS);

面试问题

  1. 说说线程池的核心参数有哪些
  2. 说说你们的corePoolSize 的数量是如何设置,超时时间如何设置
  3. 你们使用的是什么队列, 为什么使用这个队列.
  4. 你们项目是如何优化自己的线程池参数的.
  5. 当线程池还没达到 corePoolSize 的时候, 线程池里面有空闲线程, 这个时候来了一个新的任务, 线程池是创建新的线程还是使用空闲线程 ?

路过点赞, 月入10w

上一篇 下一篇

猜你喜欢

热点阅读