线程池注意事项

执行任务的时候,先使用corePoolSize范围内的线程,多出的任务放到阻塞队列,阻塞队列放满了,才会用maximumPoolSize范围内的线程。

如果阻塞队列设置成无界,有OOM的风险。

线程/线程池一定要起好名字,这样用jstack导出threaddump文件后,可以看出线程是在执行什么业务。

慎用showdownNow(),会直接把业务线程停掉,可能对业务造成影响。

自定义线程池,最好有固定的后缀,与框架的线程池区分开,这样jstack的时候可以grep 固定后缀,只看自定义线程的信息。


ExecutorService executorService = new ThreadPoolExecutor(10, 20, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingDeque<>(10), factory, new ThreadPoolExecutor.AbortPolicy());

线程池配置如上,如果有22个任务,第1-10个任务由核心线程跑,第11-20个任务放入阻塞队列,第21-22个任务由新建线程(或者释放cpu资源后的核心线程)跑,第21-22个任务的执行顺序,先于第11-20个任务。


当运行中的线程数已达到最大线程数,且阻塞队列已满时,对于新的任务,有以下策略
CallerRunsPolicy: 把新的任务交给main线程执行
DiscardPolicy: 直接舍弃
AbortPolicy: 抛异常,不影响其他线程的执行,该策略可能导致线程无法释放
DiscardOldestPolicy: 舍弃最旧的任务


public static void main(String[] args) throws Exception{
    ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("test-thread-pool-%d").build();
    ExecutorService executorService = new ThreadPoolExecutor(10, 20, 0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingDeque<>(10), factory, new ThreadPoolExecutor.AbortPolicy());

    for (int i = 1; i <= 31; i++) {
        final int j = i;
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ": " + j);
            }
        });
    }

    executorService.shutdown();
}

上述代码,线程无法正常释放,jstack导出的dump日志大量waiting on condition

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容