线程池ThreadPoolExecutor

什么是线程池

线程池(Thread Pool)是一种基于池化思想管理线程的工具,经常出现在多线程服务器中,如MySQL。线程池维护着多个线程,等待着监督管理者分配执行的任务,简单来说,就是可管理和维护以及分配线程的“池子”。

线程池的优点

1)降低资源消耗:减少创建和销毁线程的次数,让每个线程都可以多次的使用。
2)提高响应速度:任务到达时,无需等待线程创建。
3)便于管理:根据系统情况调整线程的数量,防止消耗过多内存,使用线程池可以进行统一的分配、调优和监控。
4)可扩展:线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池ScheduledThreadPoolExecutor,就允许任务延期执行或定期执行。

线程池运行的状态

线程池运行的状态,并不是用户显式设置的,而是伴随着线程池的运行,由内部来维护,有五种状态:RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED
在这里插入图片描述

运行状态说明
RUNNING线程池的初始化状态是RUNNING,处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理
SHUTDOWN调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN,线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务
STOP调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP,线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务
TIDYING当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING,当线程池变为TIDYING状态时,会执行钩子函数terminated()
TERMINATED线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED,线程池彻底终止

线程池核心参数

ThreadPoolExecutor继承自AbstractExecutorService,而AbstractExecutorService实现了ExecutorService接口,线程池的构造方法如下:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

参数说明:

参数说明
corePoolSize核心线程数
maximumPoolSize最大线程数
keepAliveTime线程空闲时间
TimeUnit时间单位
workQueue任务队列/阻塞队列
ThreadFactory线程工厂
RejectedExecutionHandler拒绝策略

任务队列/阻塞队列

使用不同的队列可以实现不一样的任务存取策略。阻塞队列有下面几种:

名称描述
ArrayBlockingQueue一个数组实现的有界阻塞队列,先进先出的原则,支持公平锁和非公平锁
LinkedBlockingQueue一个由链表结构组成的有界队列,默认长度Integer.MAX_VALUE,先进先出的原则
PriorityBlockingQueue一个支持线程优先级排序的无界队列,默认自然序列进行排序,也可以自定义compareTo()方法指定排序,不能保证同优先级元素的顺序
DelayQueue一个实现PriorityBlockingQueue实现延时获取的无界队列,在创建元素时可以指定多久才能从队列获取当前元素
SynchronousQueue一个不存储元素的队列,每一个put操作必须等到task操作,否则不能添加元素,支持公平锁和非公平锁 ,这个线程池根据需要(新任务来时)创建线程,如果有空闲线程则会重复使用,线程空闲60s后被回收
LinkedTransferQueue一个由链表结构组成的无界阻塞队列,相比其他队列多了transfer和tryTransfer方法
LinkedBlocingDeque一个由链表结构组成的双向阻塞队列,队列头和尾部都可以添加或删除元素,多线程并发时可将锁的竞争最多降低一半

拒绝策略

拒绝策略是线程池的保护部分,线程池有一个最大的容量,当线程池的任务缓存队列已满,并且线程池中的线程数目达到maximumPoolSize时,就需要拒绝掉该任务,采取任务拒绝策略,保护线程池。拒绝策略是一个接口:

public interface RejectedExecutionHandler {
	void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

用户可以通过实现这个接口去定制拒绝策略,也可以选择JDK提供的四种已有拒绝策略,其特点如下:

名称描述
ThreadPoolExecutor.AbortPolicy丢弃任务并抛出RejectedExecutionException异常,线程池默认拒绝策略
ThreadPoolExecutor.DiscardPolicy丢弃任务不抛出异常
ThreadPoolExecutor.DiscardOldestPolicy丢弃队列最前面的任务,然后重新提交被拒绝的任务
ThreadPoolExecutor. CallerRunsPolicy由调用线程(提交任务的线程)处理该任务

线程池的执行顺序

1)首先检测线程池运行状态,如果不是RUNNING,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
2)如果workerCount(已创建的线程) < corePoolSize,则创建并启动一个线程来执行新提交的任务。
3)如果workerCount >= corePoolSize,且线程池内的阻塞队列未满,则将任务添加到该阻塞队列中。
4)如果workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满,则创建并启动一个线程来执行新提交的任务。
5)如果workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值