什么是线程池
线程池是一种基于池化思想管理线程工具。
线程池的好处
降低资源消耗
: 通过重复利用已创建的线程来降低线程创建和销毁所造成的消耗。提高响应速度
: 任务到达时可以立即执行,不需要等到线程创建再来执行任务。提高线程的可管理性
: 线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会因为线程的不合理分布导致资源调度失衡,降低系统的稳定性。使用线程池可以进行统一的分配、调优和监控。
怎么使用线程池
1. Executors 方式
Executors创建方式 一般不推荐
使用,在阿里巴巴开发手册中也明确了这一点。
-
Executors.newFixedThreadPool:
创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待; -
Executors.newCachedThreadPool:
创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程; -
Executors.newSingleThreadExecutor:
创建单个线程数的线程池,它可以保证先进先出的执行顺序; -
Executors.newScheduledThreadPool:
创建一个可以执行延迟任务的线程池; -
Executors.newSingleThreadScheduledExecutor:
创建一个单线程的可以执行延迟任务的线程池; -
Executors.newWorkStealingPool:
创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK 1.8 添加】。
2. ThreadPoolExecutor
最原始创建线程池的方式,它包含了7个参数可供设置。
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
ThreadPoolExecutor参数介绍
corePoolSize
核心线程数(线程池的基本大小)当我们提交一个任务到线程池时就会创建一个线程来执行任务。当我们需要执行的任务数大于核心线程数了就不再创建, 如果我们调用了prestartAllCoreThreads()
方法线程池就会为我们提前创建好所有的基本线程。
maximumPoolSize
最大线程数:线程池允许创建的最大线程数。如果队列已经满了,且已创建的线程数小于最大线程数,则线程池就会创建新的线程来执行任务。这里有个小知识点,如果我们的队列是用的无界队列,这个参数是不会起作用的,因为我们的任务会一直往队列中加,队列永远不会满(内存允许的情况)。
keepAliveTime
最大线程数可以存活的时间,当线程中没有任务执行时,最大线程就会销毁一部分,最终保持核心线程数量的线程。
unit
单位是和keepAliveTime
存活时间配合使用的,合在一起用于设定线程的存活时间 ,参数 keepAliveTime 的时间单位有以下 7 种可选:
- TimeUnit.DAYS:天
- TimeUnit.HOURS:小时
- TimeUnit.MINUTES:分
- TimeUnit.SECONDS:秒
- TimeUnit.MILLISECONDS:毫秒
- TimeUnit.MICROSECONDS:微妙
- TimeUnit.NANOSECONDS:纳秒
workQueue
一个阻塞队列,用来存储线程池等待执行的任务,均为线程安全,它包含以下 7 种类型:
- ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。此队列按照先进先出的原则对元素进行排序
- LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。此队列按照先进先出的原则对元素进行排序,默认长度为Integer.MAX_VALUE
- SynchronousQueue:一个不存储元素的阻塞队列,即直接提交给线程不保持它们。
- PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。默认自然顺序排序,也可以定义实现CompareTo()方法指定元素排序规则
- DelayQueue:一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素。
- LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。与SynchronousQueue类似,还含有非阻塞方法。
- LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列
threadFactory
线程工厂,主要用来创建线程,默认为正常优先级、非守护线程。我们也可以通过实现ThreadFactory 来自定义线程工厂
handler
拒绝策略,拒绝处理任务时的策略,系统提供了 4 种可选:
- AbortPolicy:拒绝并抛出异常。
- CallerRunsPolicy:使用当前调用的线程来执行此任务。
- DiscardOldestPolicy:抛弃队列头部(最旧)的一个任务,并执行当前任务。
- DiscardPolicy:忽略并抛弃当前任务。
默认策略为 AbortPolicy
。
我们也可以自定义任务拒绝策略(实现下RejectedExecutionHandler
接口),比如说如果任务拒绝了我们可以记录下日志,或者重试等,根据自己的业务需求来实现。