ThreadPoolExecutor

线程池原理分析

首先要明确为什么要使用线程池,使用线程池会带来什么好处?

  • 线程是稀缺资源,不能频繁的创建。
  • 应当将其放入一个池子中,可以给其他任务进行复用。
  • 解耦作用,线程的创建于执行完全分开,方便维护。

创建一个线程池

以一个使用较多的

1
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)

为例:

  • 其中的 corePoolSize 为线程池的基本大小。
  • maximumPoolSize 为线程池最大线程大小。
  • keepAliveTimeunit 则是线程空闲后的存活时间。
  • workQueue 用于存放任务的阻塞队列。
  • handler 当队列和最大线程池都满了之后的饱和策略。

处理流程

当提交一个任务到线程池时它的执行流程是怎样的呢?

首先第一步会判断核心线程数有没有达到上限,如果没有则创建线程(会获取全局锁),满了则会将任务丢进阻塞队列。

如果队列也满了则需要判断最大线程数是否达到上限,如果没有则创建线程(获取全局锁),如果最大线程数也满了则会根据饱和策略处理。

常用的饱和策略有:

  • 直接丢弃任务。
  • 调用者线程处理。
  • 丢弃队列中的最近任务,执行当前任务。

所以当线程池完成预热之后都是将任务放入队列,接着由工作线程一个个从队列里取出执行。

合理配置线程池

线程池并不是配置越大越好,而是要根据任务的熟悉来进行划分:
如果是 CPU 密集型任务应当分配较少的线程,比如 CPU 个数相当的大小。

如果是 IO 密集型任务,由于线程并不是一直在运行,所以可以尽可能的多配置线程,比如 CPU 个数 * 2

当是一个混合型任务,可以将其拆分为 CPU 密集型任务以及 IO 密集型任务,这样来分别配置。

如果帮到你, 可以给我赞助杯咖啡☕️
0%