ThreadPoolExecutor最佳实践--如何选择线程数

去年的一篇《ThreadPoolExecutor详解》大致讲了ThreadPoolExecutor内部的代码实现。总结一下,主要有以下四点:当有任务提交的时候,会创建核心线程去执行任务;当核心线程数达到corePoolSize时,后续提交的都会进BlockingQueue中排队;当BlockingQueue满了(offer失败),就回创建临时线程;当线程总数达到maximumPoo...
摘要由CSDN通过智能技术生成

系列文章:


去年的一篇《ThreadPoolExecutor详解》大致讲了ThreadPoolExecutor内部的代码实现。

总结一下,主要有以下四点:

  • 当有任务提交的时候,会创建核心线程去执行任务(即使有核心线程空闲仍会创建);
  • 当核心线程数达到corePoolSize时,后续提交的都会进BlockingQueue中排队;
  • 当BlockingQueue满了(offer失败),就会创建临时线程(临时线程空闲超过一定时间后,会被销毁);
  • 当线程总数达到maximumPoolSize时,后续提交的任务都会被RejectedExecutionHandler拒绝。

prestartAllCoreThreads方法可以直接创建所有核心线程并启动。

BlockingQueue使用无限容量的阻塞队列(如LinkedBlockingQueue)时,不会创建临时线程(因为队列不会满),所以线程数保持corePoolSize。

BlockingQueue使用没有容量的同步队列(如SynchronousQueue)时,任务不会入队,而是直接创建临时线程去执行任务。

线程池基本模型

虽然线程池的模型被剖析的非常清晰,但是如何最高性能地使用线程池一直是一个令人纠结的问题,其中最主要的问题就是如何决定线程池的大小

这篇文章会以量化测试的方式分析:何种情况线程池应该使用多少线程数。

1. 计算密集型任务与IO密集型任务

大多数刚接触线程池的人会认为有一个准确的值作为线程数能让线程池适用在程序的各个地方。然而大多数情况下并没有放之四海而皆准的值,很多时候我们要根据任务类型来决定线程池大小以达到最佳性能。

计算密集型任务以CPU计算为主,这个过程中会涉及到一些内存数据的存取(速度明显快于IO),执行任务时CPU处于忙碌状态。

IO密集型任务以IO为主,比如读写磁盘文件、读写数据库、网络请求等阻塞操作,执行IO操作时,CPU处于等待状态,等待过程中操作系统会把CPU时间片分给其他线程。

2. 计算密集型任务

下面写一个计算密集型任务的例子:

public class ComputeThreadPoolTest {
   

    final static ThreadPoolExecutor computeExecutor;

    final static List<Callable<Long>> computeTasks;

    final static int task_count = 5000;

    static {
   
        computeExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);

        // 创建5000个计算任务
        computeTasks = new ArrayList<>(task_count);
        for (int i = 0; i < task_count; i++) {
   
            computeTasks.add(new ComputeTask());
        }
    }

    static class ComputeTask implements Callable<Long> {
   
        // 计算一至五十万数的总和(纯计算任务)
        @Override
        public Long call() {
   
            long sum = 0;
            for (long i = 0; i < 50_0000; i++) {
   
                sum += i;
            }
            return sum;
        }
    }

    public static void main(String[] args) throws InterruptedException {
   
        // 我电脑是四核处理器
        int processorsCount = Runtime.getRuntime().availableProcessors();
        // 逐一增加线程池的线程数
        for (int i = 1; i <=  processorsCount * 5; i++) {
   
            computeExecutor.setCorePoolSize(i);
            computeExecutor.setMaximumPoolSize(i);
            computeExecutor.prestartAllCoreThreads
  • 10
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值