线程池
核心概念: 线程复用,任务调度,资源管理
- 线程复用: 线程池通过维护一个线程集合,避免了频繁创建和销毁线程的开销,降低资源消耗,提高系统响应速度。
- 任务调度: 线程池统一管理和调度提交的任务,将任务放入阻塞队列中,并由工作线程从队列中取出任务执行,实现了任务的生产者-消费者模式。
- 资源管理: 线程池可以限制线程的最大数量,防止无限制创建线程导致系统资源耗尽,提高线程的可管理性。
关键事实:
- 线程池的优势: 降低资源消耗、提高响应速度、提高线程可管理性。
- ThreadPoolExecutor: Java 线程池的核心实现类,提供了更灵活和强大的线程池配置,允许自定义核心线程数、最大线程数、线程存活时间、工作队列和拒绝策略等参数。
- ThreadPoolExecutor 的参数:
corePoolSize
: 核心线程数,线程池基本保持的线程数量。maximumPoolSize
: 最大线程数,线程池允许的最大线程数量。keepAliveTime
: 线程存活时间,非核心线程空闲时的最大存活时间,超过这个时间会被回收。workQueue
: 工作队列,用于存储等待执行的任务,常见的类型有ArrayBlockingQueue
、LinkedBlockingQueue
、SynchronousQueue
等。RejectedExecutionHandler
: 拒绝策略,当任务队列已满且线程数达到最大值时,用于处理新提交的任务,Java 提供了四种默认策略 (AbortPolicy
,CallerRunsPolicy
,DiscardOldestPolicy
,DiscardPolicy
),也支持自定义。
- 常见线程池类型 (Executors 工厂方法):
newFixedThreadPool
: 固定大小线程池,核心线程数和最大线程数相等,使用无界队列LinkedBlockingQueue
,适用于任务量较稳定,需要保证响应速度的场景。缺点:可能导致 OOM (OutOfMemoryError),因为无界队列可能堆积大量请求。newSingleThreadExecutor
: 单线程线程池,只有一个核心线程,使用无界队列LinkedBlockingQueue
,保证任务顺序执行。缺点:同newFixedThreadPool
,可能导致 OOM。newCachedThreadPool
: 可缓存线程池,核心线程数为 0,最大线程数无上限 (Integer.MAX_VALUE
),使用同步队列SynchronousQueue
,线程空闲超过一定时间 (keepAliveTime
) 会被回收,适用于任务数量波动大,但每个任务执行时间较短的场景。缺点:可能创建大量线程,导致 OOM.
- 关闭线程池:
shutdown()
: 平缓关闭,线程池不再接收新任务,但会继续执行完已提交的任务.shutdownNow()
: 立即关闭,线程池立即停止接收新任务,并尝试中断正在执行的任务,返回未执行的任务列表.
- FutureTask: 用于封装 Callable 或 Runnable 任务,可以获取异步任务的执行结果 (
get()
方法会阻塞等待结果),并监控任务状态 (isDone()
,isCancelled()
) 和取消任务 (cancel()
). submit
方法: 向线程池提交任务,可以提交Runnable
或Callable
类型的任务,并返回一个Future
对象,用于获取任务执行状态和结果。submit(Runnable)
返回Future<?>
,submit(Callable)
返回Future<T>
,submit(Runnable, T result)
可以指定Runnable
任务完成后的返回值.- ThreadPoolExecutor 内部状态: 通过
ctl
原子变量同时存储线程池运行状态 (runState) 和工作线程数量 (workerCount),实现了高效的状态管理. 线程池状态包括RUNNING
,SHUTDOWN
,STOP
,TIDYING
,TERMINATED
等. - 任务执行原理 (execute 方法):
- 检查核心线程数: 若当前线程数小于
corePoolSize
,则创建新线程执行任务. - 尝试加入工作队列: 若当前线程数已达到
corePoolSize
,则尝试将任务加入workQueue
. - 检查最大线程数: 若工作队列已满,且当前线程数小于
maximumPoolSize
,则创建新线程执行任务. - 拒绝执行: 若工作队列已满,且当前线程数已达到
maximumPoolSize
,则执行拒绝策略 (RejectedExecutionHandler
).
- 检查核心线程数: 若当前线程数小于
总结与延伸:
线程池是 Java 并发编程中管理和控制线程的重要机制,合理使用线程池可以显著提高多线程程序的性能和资源利用率. ThreadPoolExecutor
提供了丰富的配置选项,可以根据不同的应用场景进行精细化调优. 在实际开发中,应避免使用 Executors
工厂方法创建线程池,而是手动创建 ThreadPoolExecutor
实例,并根据任务特性和系统资源合理配置线程池参数,例如:CPU 密集型任务可设置较小的线程数 (Ncpu+1),IO 密集型任务可设置较大的线程数 (Ncpu2) 或更多. 同时,应尽量使用有界队列,并自定义拒绝策略,防止线程池资源耗尽,保证系统的稳定性和可靠性. 监控线程池的状态 (例如:getTaskCount()
, getActiveCount()
, getCompletedTaskCount()
) 也是非常重要的,可以帮助我们了解线程池的运行状况*,及时发现和解决潜在问题.
为什么要有线程池?
线程池的出现是为了解决以下几个主要问题,并提供更高效、更可控的线程管理方式:
-
减少线程创建和销毁的开销:
- 线程生命周期开销: 线程的创建和销毁是比较昂贵的操作,涉及到操作系统资源的分配和回收. 频繁地创建和销毁线程会消耗大量的系统资源,降低程序性能.
- 线程池复用: 线程池通过复用已创建的线程来执行新的任务,避免了线程创建和销毁的开销,提高了程序的响应速度和执行效率.
-
提高系统资源的利用率:
-
按需创建: 线程池可以根据实际任务需求动态地创建和管理线程,避免了创建过多线程导致系统资源浪费,或者线程不足导致任务堆积.
- 资源限制: 线程池可以限制线程的最大数量,防止无限制地创建线程导致系统资源耗尽,保证系统的稳定性.
-
提高程序的响应速度:
-
任务排队: 当有新任务到达时,线程池可以立即从线程池中获取空闲线程来执行任务,或者将任务放入队列中等待执行,而不是等待新的线程创建完成. 这缩短了任务的等待时间,提高了程序的响应速度.
- 并发处理能力: 线程池可以并发执行多个任务,提高了程序的整体处理能力和吞吐量.
-
提供更方便的线程管理和监控:
-
统一管理: 线程池可以统一管理线程的创建、销毁、调度和监控,简化了并发编程的复杂性.
- 监控和调优: 线程池提供了监控线程池状态 (例如,活跃线程数、队列长度、已完成任务数等) 的接口,方便开发者了解线程池的运行状况,并进行性能调优.
总结: 线程池的核心价值在于线程复用和资源管理,它可以显著降低线程管理的开销,提高系统资源的利用率,并提升程序的响应速度和并发性能.
Java 中实现和管理线程池有哪些方式? 请简单举例如何使用。
Java 中实现和管理线程池主要通过 java.util.concurrent
包下的 ExecutorService
接口及其实现类 ThreadPoolExecutor
和 ScheduledThreadPoolExecutor
.
1. 使用 Executors
工厂类 (简化方式):
Executors
类提供了一系列静态工厂方法,可以快速创建几种常用的线程池:
-
Executors.newFixedThreadPool(int nThreads)
: 创建固定大小的线程池. 核心线程数和最大线程数都为nThreads
,使用LinkedBlockingQueue
作为任务队列 (无界队列). -
Executors.newCachedThreadPool()
: 创建可缓存的线程池. 核心线程数为 0,最大线程数为Integer.MAX_VALUE
,使用SynchronousQueue
作为任务队列 (直接提交队列). 线程空闲超过 60 秒会被回收. -
Executors.newSingleThreadExecutor()
: 创建单线程的线程池. 核心线程数和最大线程数都为 1,使用LinkedBlockingQueue
作为任务队列 (无界队列). 保证所有任务按照提交顺序依次执行. -
Executors.newScheduledThreadPool(int corePoolSize)
和Executors.newSingleThreadScheduledExecutor()
: 创建定时或周期性执行任务的线程池 (ScheduledExecutorService
接口).
2. 使用 ThreadPoolExecutor
类 (更灵活、更精细的控制):
直接使用 ThreadPoolExecutor
类可以更灵活地配置线程池的各种参数,例如核心线程数、最大线程数、线程空闲时间、任务队列、拒绝策略等.
import java.util.concurrent.*;
public class ThreadPoolExecutorExample {
public static void main(String[] args) {
int corePoolSize = 2;
int maxPoolSize = 5;
long keepAliveTime = 60L;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100); // 有界队列
ThreadFactory threadFactory = Executors.defaultThreadFactory();
RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy(); // 拒绝策略
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
keepAliveTime,
unit,
workQueue,
threadFactory,
rejectedExecutionHandler
);
for (int i = 0; i < 15; i++) {
final int taskIndex = i;
threadPoolExecutor.execute(() -> {
System.out.println(Thread.currentThread().getName() + " is running task " + taskIndex);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
threadPoolExecutor.shutdown();
}
}
总结: Executors
工厂类提供了快速创建常用线程池的便捷方式,而 ThreadPoolExecutor
类则提供了更精细的配置和控制能力. 选择哪种方式取决于具体的应用场景和需求.
为什么很多公司不允许使用 Executors
去创建线程池? 那么推荐怎么使用呢?
虽然 Executors
工厂类提供了创建线程池的便利性,但很多公司在代码规范中会禁止或不推荐使用 Executors
创建线程池,主要原因在于 Executors
创建的某些线程池存在潜在的资源耗尽风险,以及缺乏足够的控制和监控能力.
Executors
创建线程池的潜在问题:
-
FixedThreadPool
和SingleThreadExecutor
使用无界队列LinkedBlockingQueue
:- OOM 风险:
LinkedBlockingQueue
是无界队列,这意味着当所有核心线程都在忙碌时,新提交的任务会无限地加入到队列中等待. 如果任务提交速度远超于任务处理速度,队列可能会无限膨胀,最终导致 OOM (OutOfMemoryError) 内存溢出. - 资源耗尽: 虽然理论上是无界,但实际上受限于 JVM 堆内存大小. 当大量任务堆积在队列中时,会占用大量内存资源,可能导致系统性能下降甚至崩溃.
-
CachedThreadPool
使用SynchronousQueue
和过多的最大线程数: -
线程数量失控:
CachedThreadPool
的最大线程数设置为Integer.MAX_VALUE
,几乎是无限制的. 在高并发场景下,如果任务提交速度很快,CachedThreadPool
可能会快速创建大量线程,超出系统承受能力,导致 CPU 飙升、系统 load 过高、甚至 系统崩溃. - 频繁线程创建销毁:
CachedThreadPool
的线程空闲时间较短 (60 秒),如果任务执行时间短且频率高,会导致频繁地创建和销毁线程,增加系统开销,降低性能.
- OOM 风险:
推荐使用 ThreadPoolExecutor
手动创建线程池:
为了避免 Executors
创建线程池的潜在问题,并获得更精细的控制,推荐直接使用 ThreadPoolExecutor
类手动创建线程池.
手动创建 ThreadPoolExecutor
的优势:
- 可配置有界队列: 可以根据实际需求选择有界队列 (例如
ArrayBlockingQueue
,LinkedBlockingQueue
(指定容量)),限制任务队列的长度,防止任务无限堆积导致 OOM. - 可配置拒绝策略: 可以根据实际需求选择合适的拒绝策略 (例如
AbortPolicy
,CallerRunsPolicy
,DiscardPolicy
,DiscardOldestPolicy
),处理当队列满且线程数达到最大值时新提交的任务,避免任务丢失或系统异常. - 更精细的参数调优: 可以根据应用的特点和性能需求,灵活地配置核心线程数、最大线程数、线程空闲时间、线程工厂等参数,进行更精细的性能调优.
- 更强的监控能力:
ThreadPoolExecutor
提供了更丰富的监控接口,可以方便地获取线程池的各种运行状态指标,进行更全面的监控和分析.
总结: Executors
工厂类提供的线程池虽然方便易用,但在某些场景下存在资源耗尽和控制不足的风险. 推荐在生产环境中使用 ThreadPoolExecutor
手动创建线程池,并根据实际需求合理配置各项参数,以确保线程池的稳定性和性能.
ThreadPoolExecutor
有哪些核心的配置参数? 请简要说明
ThreadPoolExecutor
的核心配置参数决定了线程池的行为和性能,主要包括以下几个:
-
corePoolSize
(核心线程数):- 含义: 线程池常驻的线程数量,即使这些线程处于空闲状态,也不会被回收 (除非设置了
allowCoreThreadTimeOut
). - 作用: 保证线程池基本的并发处理能力. 当有新任务提交时,线程池会优先使用核心线程池中的线程来执行任务.
- 设置建议: 根据CPU 核心数和任务类型 (CPU 密集型或 IO 密集型) 来设置. 对于 CPU 密集型任务,可以设置为 CPU 核心数; 对于 IO 密集型任务,可以适当增加.
-
maximumPoolSize
(最大线程数): -
含义: 线程池最多可以创建的线程数量. 当任务队列满了,且当前线程数小于最大线程数时,线程池会创建新的线程来执行任务.
- 作用: 应对突发的高并发请求,提高线程池的峰值处理能力.
- 设置建议: 应该大于等于核心线程数. 设置过大可能会导致系统资源耗尽,设置过小可能无法充分利用系统资源. 需要根据系统资源和任务特性综合考虑.
-
keepAliveTime
(线程空闲时间): -
含义: 当线程池中线程数量超过核心线程数时,空闲线程在等待新任务的最长存活时间. 超过这个时间,空闲线程会被回收,直到线程池的线程数减少到核心线程数.
- 作用: 动态调整线程池的线程数量,在任务低峰期回收多余的线程,减少资源消耗.
- 单位: 需要配合
unit
参数指定时间单位 (例如TimeUnit.SECONDS
,TimeUnit.MILLISECONDS
). - 设置建议: 根据任务的平均执行时间和任务的到达频率来设置. 如果任务执行时间短且频率高,可以设置较短的空闲时间; 如果任务执行时间长且频率低,可以设置较长的空闲时间.
-
unit
(时间单位): -
含义:
keepAliveTime
参数的时间单位. 例如TimeUnit.SECONDS
,TimeUnit.MILLISECONDS
,TimeUnit.MINUTES
等. - 作用: 指定
keepAliveTime
的时间单位. -
workQueue
(任务队列): -
含义: 用于缓存等待执行的任务的队列. 当核心线程都在忙碌时,新提交的任务会先进入任务队列排队等待.
- 类型: 常见的任务队列类型包括:
ArrayBlockingQueue
: 有界数组队列,FIFO. 容量固定,可以防止 OOM,但可能导致任务拒绝.LinkedBlockingQueue
: 有界/无界链表队列,FIFO. 容量可以动态增长 (无界时),但可能导致 OOM (无界时).SynchronousQueue
: 直接提交队列,不缓存任务. 每个插入操作必须等待一个移除操作,反之亦然. 适用于线程数可以动态增长的场景 (例如CachedThreadPool
).PriorityBlockingQueue
: 无界优先级队列. 任务会根据优先级排序,优先级高的任务先执行.
- 作用: 缓冲任务,平衡生产者和消费者的速度差异,控制任务的排队策略.
- 设置建议: 根据任务的特性和系统资源来选择合适的队列类型和容量. 对于有界队列,需要权衡队列容量大小与任务拒绝策略. 对于无界队列,需要注意 OOM 风险.
-
threadFactory
(线程工厂): -
含义: 用于创建新线程的工厂. 可以自定义线程的创建方式,例如设置线程名称、是否守护线程、线程优先级等.
- 默认实现:
Executors.defaultThreadFactory()
提供默认的线程工厂实现. - 作用: 定制化线程的创建过程. 例如,可以为线程设置有意义的名称,方便线程池的监控和问题排查.
-
rejectedExecutionHandler
(拒绝策略): -
含义: 当任务队列已满且线程池线程数已达到最大线程数时,新提交的任务会被拒绝执行.
rejectedExecutionHandler
定义了如何处理被拒绝的任务. - 常见策略: 包括
AbortPolicy
,CallerRunsPolicy
,DiscardPolicy
,DiscardOldestPolicy
(详细解释见下文). - 作用: 控制线程池在超负荷情况下的行为,保护系统资源,保证系统的稳定性.
- 设置建议: 根据业务场景和对任务丢失的容忍度来选择合适的拒绝策略.
- 含义: 线程池常驻的线程数量,即使这些线程处于空闲状态,也不会被回收 (除非设置了
总结: ThreadPoolExecutor
的核心参数共同决定了线程池的线程数量、任务队列、线程回收策略、以及任务拒绝策略. 合理配置这些参数是构建高效、稳定的线程池的关键.
ThreadPoolExecutor
可以创建哪是哪三种线程池呢?
虽然 ThreadPoolExecutor
本身是一个类,而不是 "创建三种线程池" 的工厂方法,但我们通常会根据 ThreadPoolExecutor
的不同配置参数组合,来模拟 Executors
工厂类创建的三种常用线程池类型,以及一些其他的变体. 这三种 "模拟" 的线程池类型分别是:
-
FixedThreadPool
(固定大小线程池):- 模拟配置:
corePoolSize
=maximumPoolSize
=nThreads
(指定的线程数)workQueue
=LinkedBlockingQueue
(无界队列)
- 特点: 线程池中线程数量固定不变,始终保持
nThreads
个线程. 使用无界队列,任务队列可以无限增长 (理论上). - 适用场景: 适用于任务量比较稳定,需要限制并发线程数的场景. 例如,服务器连接处理、固定数量的任务并行处理等.
- 风险: 使用无界队列,可能导致 OOM 风险.
-
CachedThreadPool
(可缓存线程池): -
模拟配置:
corePoolSize
= 0 (核心线程数为 0)maximumPoolSize
= Integer.MAX_VALUE (最大线程数无限制)keepAliveTime
= 60 秒 (线程空闲时间 60 秒)workQueue
=SynchronousQueue
(直接提交队列)
- 特点: 线程池初始线程数为 0,当有新任务提交时,如果线程池中有空闲线程,则复用空闲线程; 如果没有空闲线程,则创建新的线程. 线程空闲超过 60 秒会被回收. 使用直接提交队列,任务不会排队等待,而是直接提交给线程执行.
- 适用场景: 适用于任务执行时间短、任务数量突发性高的场景. 例如,处理大量短连接请求.
- 风险: 最大线程数无限制,可能导致线程数量失控,系统资源耗尽.
-
SingleThreadExecutor
(单线程线程池): -
模拟配置:
corePoolSize
=maximumPoolSize
= 1 (核心线程数和最大线程数都为 1)workQueue
=LinkedBlockingQueue
(无界队列)
- 特点: 线程池中只有一个线程,所有提交的任务都按照 FIFO 顺序依次执行. 保证任务的顺序执行. 使用无界队列,任务队列可以无限增长 (理论上).
- 适用场景: 适用于需要顺序执行任务的场景,例如,单线程任务调度、消息队列的顺序消费等.
- 风险: 使用无界队列,可能导致 OOM 风险.
- 模拟配置:
总结: ThreadPoolExecutor
通过不同的参数配置,可以灵活地创建各种类型的线程池,以适应不同的并发场景需求. 理解这些参数的含义和组合方式,可以帮助我们更好地使用线程池.
当队列满了并且 worker 的数量达到 maxSize 的时候,会怎么样?
当线程池的任务队列 (workQueue
) 已满,并且当前工作线程数 (workerCount
) 已经达到最大线程数 (maximumPoolSize
) 时,如果再有新的任务提交到线程池,线程池会执行拒绝策略 (rejectedExecutionHandler
) 来处理这些无法执行的新任务.
拒绝策略的触发条件:
- 任务队列已满:
workQueue.offer(task)
返回false
,表示队列已满,无法再添加新任务. - 工作线程数已达最大值:
workerCount >= maximumPoolSize
,表示线程池已经创建了最大数量的线程,无法再创建新的线程.
拒绝策略的处理方式: 由 rejectedExecutionHandler
决定,常见的策略包括 (详细解释见下文):
AbortPolicy
(默认策略): 直接抛出RejectedExecutionException
异常,终止任务执行,调用者可以捕获异常进行处理.CallerRunsPolicy
: 由提交任务的线程 (调用者线程) 自己执行被拒绝的任务. 降低了任务提交速度,但保证了任务不会被丢失.DiscardPolicy
: 直接丢弃被拒绝的任务,不抛出异常,也不做任何处理. 任务会被默默地丢弃,可能导致数据丢失.DiscardOldestPolicy
: 丢弃队列中队首 (最旧) 的任务,然后尝试重新提交当前被拒绝的任务. 为新任务腾出空间,但可能导致旧任务丢失.
总结: 当线程池超负荷运行时,拒绝策略是保护线程池和系统资源的重要机制. 选择合适的拒绝策略需要根据具体的业务场景和对任务丢失的容忍度来权衡.
说说 ThreadPoolExecutor
有哪些 RejectedExecutionHandler
策略? 默认是什么策略?
ThreadPoolExecutor
提供了四种内置的 RejectedExecutionHandler
策略,用于处理被拒绝的任务. 开发者也可以自定义 RejectedExecutionHandler
策略.
内置的 RejectedExecutionHandler
策略:
-
AbortPolicy
(默认策略):- 行为: 当任务被拒绝时,
AbortPolicy
会抛出RejectedExecutionException
异常. - 特点: 立即终止任务执行,抛出异常通知调用者任务被拒绝. 是
ThreadPoolExecutor
的默认拒绝策略. - 适用场景: 适用于不允许任务丢失的场景,希望及时发现和处理任务被拒绝的情况. 调用者可以捕获
RejectedExecutionException
异常,并进行相应的处理 (例如,重试任务、记录日志、报警等). -
CallerRunsPolicy
: -
行为: 当任务被拒绝时,
CallerRunsPolicy
会由提交任务的线程 (调用者线程) 自己同步执行被拒绝的任务. - 特点: 不会抛出异常,不会丢弃任务,而是将任务退回给调用者线程执行. 降低了任务提交速度,相当于将一部分任务处理压力转移给调用者线程.
- 适用场景: 适用于不希望任务被丢弃,并且允许降低任务提交速度的场景. 例如,流量削峰、任务降级处理等.
-
DiscardPolicy
: -
行为: 当任务被拒绝时,
DiscardPolicy
会直接丢弃被拒绝的任务,不做任何处理,也不抛出异常. - 特点: 默默丢弃任务,不通知调用者,不抛出异常. 简单粗暴,但可能导致数据丢失.
- 适用场景: 适用于允许任务丢失的场景,例如,日志记录 (可以容忍少量日志丢失)、某些监控数据采集等.
-
DiscardOldestPolicy
: -
行为: 当任务被拒绝时,
DiscardOldestPolicy
会丢弃队列中队首 (最旧) 的任务,然后尝试重新提交当前被拒绝的任务. - 特点: 丢弃旧任务,为新任务腾出空间,尝试执行新任务. 一定程度上保证了新任务的执行,但可能导致旧任务丢失.
- 适用场景: 适用于希望优先处理新任务,可以容忍丢弃旧任务的场景. 例如,缓存更新 (优先更新最新的数据)、某些实时性要求较高的任务处理等. 注意:
DiscardOldestPolicy
需要配合有界队列使用,否则可能会一直丢弃队首任务,导致队列为空.
- 行为: 当任务被拒绝时,
默认拒绝策略: ThreadPoolExecutor
的默认拒绝策略是 AbortPolicy
.
自定义拒绝策略: 开发者可以实现 RejectedExecutionHandler
接口,自定义更复杂的拒绝策略,例如:
- 记录日志: 将拒绝的任务信息记录到日志中,方便后续分析和处理.
- 报警通知: 当任务被拒绝时,发送报警通知 (例如,邮件、短信) 给运维人员.
- 持久化存储: 将被拒绝的任务持久化存储到数据库或消息队列中,稍后重试执行.
选择建议: 选择合适的拒绝策略需要根据具体的业务场景和需求来权衡. AbortPolicy
(默认策略) 适用于需要及时发现和处理任务拒绝的情况; CallerRunsPolicy
适用于不希望任务被丢弃,可以降低任务提交速度的场景; DiscardPolicy
适用于允许任务丢失的场景; DiscardOldestPolicy
适用于希望优先处理新任务的场景. 自定义拒绝策略可以提供更灵活的处理方式.
简要说下线程池的任务执行机制? execute
–> addWorker
–> runWorker
(getTask
)
ThreadPoolExecutor
的任务执行机制可以用以下简要流程概括:
-
execute(Runnable command)
(任务提交):- 当客户端代码调用
threadPoolExecutor.execute(Runnable task)
方法提交任务时,线程池开始执行任务提交流程. -
addWorker(Runnable firstTask, boolean core)
(添加 Worker 线程): -
execute()
方法内部会调用addWorker()
方法来尝试添加 Worker 线程来执行任务. - Worker 线程:
Worker
是ThreadPoolExecutor
的内部类,它实现了Runnable
接口,负责执行任务. 每个Worker
对象都持有一个线程 (Thread
),并维护着一个任务队列 (workQueue
) 的引用. - 添加 Worker 的条件判断:
addWorker()
方法会根据以下条件判断是否需要添加新的 Worker 线程:- 线程池状态: 线程池必须
- 当客户端代码调用