/usr/lib/jvm/java-1.11.0-openjdk-amd64!/java.base/java/util/concurrent/ThreadPoolExecutor.class
实现本质:线程安全的工作队列来链接工作者线程和客户端线程,客户端线程把任务放到工作队列,然后工作者线程把任务从工作队列中取出并且执行.
核心线程在完成任务后不会被销毁,而是在循环getTask()的时候被阻塞队列阻塞住,只有当线程数大于核心线程的时候,普通线程就会被销毁.
我们在解析线程池的constructor之前,先介绍一下各个参数的意义
-
corePoolSize 核心线程数,即实际线程池没有任务需要执行的时候的大小,只有当工作队列满了的的时候,才会创建超出这个参数的线程.
1.当前线程数量 < corePoolSize 的时候,线程池会创建一个新线程来执行任务
2.当前线程数量>=corePoolSize的时候,线程会被放到阻塞队列中. -
maxPoolSize 线程池允许的最大线程数
1.当前线程数量<maxPoolSize的时候,如果阻塞队列满了,就会创建新的线程
2.当前线程数量>=maxPoolSize,根据策略决定任务的处理方式
3.使用无界队列的时候,这个参数作废
具体策略:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
- keepAliveTime 线程存活时间 当线程池允许线程超时而且运行中的线程超过corePoolSize的时候,会按照这个变量设置时间关闭线程,这个是针对非核心线程

-
TimeUnit: keepAliveTime的单位
-
BlockingQueue workQueue 缓冲队列
三种排队策略
1.直接提交。工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
2.无界队列。使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
3.有界队列。当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。
- RejectedExecutionHandler handler:拒绝处理任务类(默认:AbortPolicy 会抛异常)
AbortPolicy:直接抛出异常,默认策略;
CallerRunsPolicy:用调用者所在的线程来执行任务;
DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
DiscardPolicy:直接丢弃任务;
当然也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务 - threadFactory:创建线程的工厂,通过自定义的线程工厂可以给每个新建的线程设置一个具有识别度的线程名。默认为DefaultThreadFactory
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
this.ctl = new AtomicInteger(ctlOf(-536870912, 0));
this.mainLock = new ReentrantLock(); //重入锁
this.workers = new HashSet(); //workers是Hashset? why?
this.termination = this.mainLock.newCondition();
if (corePoolSize >= 0 && maximumPoolSize > 0 && maximumPoolSize >= corePoolSize && keepAliveTime >= 0L) {
if (workQueue != null && threadFactory != null && handler != null) {
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);

本文详细介绍了JAVA线程池的工作原理,包括核心线程数、最大线程数、存活时间、阻塞队列等关键参数。讲解了线程池的四种类型:newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor和newScheduledThreadPool的特性。同时,分析了execute方法源码,阐述了任务执行流程和线程管理策略。
最低0.47元/天 解锁文章
1202

被折叠的 条评论
为什么被折叠?



