线程池常用参数分析,以及要如何设置

个人博客地址sillybaka的博客

在面试中被问到了这个问题:使用过线程池吗?有什么参数?怎么设置参数?为什么要这样设置?具体场景呢? —— 当时的我不怎么会哈哈

所以作出以下总结

常用的构造方法

public ThreadPoolExecutor(int corePoolSize, // 核心线程数
int maximumPoolSize, // 线程池中最大线程数
long keepAliveTime, // 空闲线程保持存活的时间
TimeUnit unit,
BlockingQueue<Runnable> workQueue // 核心线程的任务队列

​ )

1、corePoolSize ,核心线程数 --> 线程池中最主要的线程,用于处理任务队列中的任务

2、maximumPoolSize, 线程池中最大线程数 --> 包含了核心线程+普通线程,不能超过最大线程数

3、keepAliveTime, 空闲线程保持存活的时间 --> 空闲普通线程最长能够存活的时间,因为如果普通线程空闲,就说明核心线程就已经足够处理所有任务

4、workQueue,线程的任务队列 --> 每个线程都线程监听该队列,暂时无法处理的任务会存放在该阻塞队列中

线程池的工作流程

源码分析 —— ThreadPoolExecutor#execute() —— 向线程池提交任务

public void execute(Runnable command) {
 if (command == null)
     throw new NullPointerException();

 // 线程池状态的全局变量 包含 线程池是否运行 + 线程数量 ,用位运算进行状态压缩
 int c = ctl.get();

 // 1、线程数是否小于核心线程数
 if (workerCountOf(c) < corePoolSize) {
     // 2、尝试创建新的核心线程,并将任务分配给核心线程
     if (addWorker(command, true))
         return;
     // 重试获取线程池状态
     c = ctl.get();
 }
 // 3、如果线程池仍在run,并且任务队列未满(能够添加任务成功)
 if (isRunning(c) && workQueue.offer(command)) {
     // 这里双重校验看线程池是否被关掉
     int recheck = ctl.get();
     // 如果线程池被关掉了,就移除该任务 
     if (! isRunning(recheck) && remove(command))
         // 并且交给拒绝策略来处理
         reject(command);

     // 这个分支应该是创建核心线程失败之后,并且线程池中没有线程时 才会到达,创建一个空的普通线程
     else if (workerCountOf(recheck) == 0)
         addWorker(null, false);
 }
 // 4、任务队列满了 --> 看能否创建普通线程处理这个任务(即看看 线程数是否已满) 
 else if (!addWorker(command, false))
     // 线程数已满 则交给拒绝策略来处理
     reject(command);
}

流程图

  1. 如果当前正在运行的线程数小于corePoolSize,则创建新的线程并分配任务给它(这些线程会监听workQueue)
  2. 如果线程数 大于等于corePoolSize,并且任务队列workQueue未满,则将任务放入任务队列
  3. 如果workQueue满了,并且线程池线程数 小于maximumPoolSize,则创建新的线程去做这个任务
  4. 否则,就将任务交给拒绝策略处理器

那么,keepAliveTime用在了哪里呢?是如何判定一个线程空闲时间超过了这个时间呢?

在内部类**Worker类(即线程池中的线程)**中我们可以看到它的run方法(实现Runnable的接口)

image-20221127211903124

再往下看,就是具体的线程执行流程

image-20221127212439610

再看看 getTask() 的实际逻辑

image-20221127214701321
  1. 线程池中的每一个线程(Worker)在run了之后,就会不断地从任务队列中获取任务
  2. 如果线程数大于corePoolSzie,并且某线程超过了keepAliveTime没有获取到任务,就会再次判断任务队列是否为空,如果任务队列仍为空,该线程就会被清除(空闲线程 + 超过keepAliveTime没有任务做)

参数设置

线程池中的线程数需要根据实际的使用场景来设置,根据不同系统的特性又可以分为: 1、CPU密集型 ; 2、IO密集型

CPU密集型

cpu密集型,那就是使用cpu的时间会占绝大多数,只有少量的时间会用来IO,所以很少会有线程因为IO而阻塞所以线程数可以适当的少一点(每一个线程都一直执行,让不出cpu资源,更多也没用)

所以一般的核心线程数corePoolSize会设置为:

计算机的CPU核数+1(因为最多只能同时并发运行cpu的核数那么多个线程,+1是考虑到那少部分因为IO而阻塞的线程)

IO密集型

io密集型,那就是IO的时间会占大多数,线程的大部分时间都处于阻塞态当中,只有少部分的时间会使用到cpu,所以线程数应该多一点(因为每个线程大部分时间都在阻塞,所以就需要其他非阻塞线程来使用cpu资源)

所以一般的核心线程数corePoolSize会设置为: cpu的核数 * 2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值