概述
线程池是管理java线程生命周期的工具
- 降低资源消耗。通过池化技术能够重复利用已创建的线程,降低线程频繁创建和销毁造成的资源消耗
- 提高线程的可管理性。无需程序员手动销毁线程,控制线程创建的数量,避免无限制的创建影响系统稳定性
线程池的运行机制
线程池的核心参数
- corePoolSize(必需):核心线程数量。默认情况下,核心线程会一直存活,但是当allowCoreThreadTimeout 设置为true时,核心线程也会超时回收
- maximumPoolSize(必需):最大线程数量,当线程池内的线程数量到达该数之后,后续的新任务将交由拒绝策略处理
- keepAliveTime(必需):线程闲置超时时长。如果闲置线程的时间超过该时长,非核心线程就会被回收,如果allowCoreThreadTimeout 设置为true时,核心线程也会超时回收
- unit(必需):keepAliveTime参数的时间单位
- workQueue(必需):线程等待队列即任务等待的队列
- threadFactory(可选):线程工厂,用于指定线程池创建新线程的方式
- handler(可选):拒绝策略,当到达最大线程数时需要执行的拒绝策略, 默认为AbortPolicy即丢弃任务并抛异常
提交任务的流程
线程池实现类——ThreadPoolExecutor
构造方法 | 参数说明 |
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) | corePoolSize:核心线程池大小 maximumPoolSize:最大线程池大小 keepAliveTime:当线程数>核心线程数时,这是 多余线程在任务执行完成后最大的存活时间 unit:时间单位 workQueue:线程等待队列即任务等待的队列 |
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) | corePoolSize:核心线程池大小 maximumPoolSize:最大线程池大小 keepAliveTime:当线程数>核心线程数时,这是 多余线程在任务执行完成后最大的存活时间 unit:时间单位 workQueue:线程等待队列即任务等待的队列 threadFactory:线程创建工厂 |
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) | corePoolSize:核心线程池大小 maximumPoolSize:最大线程池大小 keepAliveTime:当线程数>核心线程数时,这是 多余线程在任务执行完成后最大的存活时间 unit:时间单位 workQueue:线程等待队列即任务等待的队列 handler:拒绝执行某个线程的策略LinkedBlockingQueue |
LinkedBlockingQueue<Runnable> 队列默认size=Integer.MAX_VALUE,即是一个无界队列 底层实现是链表;读和写使用的是两个不同的锁,所以是读写分离的队列。 | 阻塞操作: take();//当队列中无元素时,阻塞等待 put();//当队满时阻塞等待 非阻塞操作: poll();//当队列为null时,返回null offer();//堆满时return false; |
功能线程池
Executors已经为我们封装好了四种常见的功能线程池:
- 定长线程池(FixedThreadPool)
- 定时线程池(ScheduledThreadPool )
- 可缓存线程池(CachedThreadPool)
- 单线程化线程池(SingleThreadExecutor)
从结构图中能看到四种线程池的真正实现类是ThreadPoolExecutor
线程池类型
1、newScheduledThreadPool 调度型线程池
- 支持定时及周期性的执行任务,提交任务时支持设置任务的调度周期
- 只限制了核心线程数,也就是最大线程数为Integer.MAX_VALUE,当添加任务的速度大于线程池处理任务的速度,可能会创建大量的线程,消耗资源,甚至导致OOM
1.1 构造
构造方法 | 参数 |
newScheduledThreadPool(int corePoolSize) | corePoolSize:corePoolSize maximumPoolSize:Integer.MAX_VALUE keepAliveTime:0 unit:NANOSECONDS workQueue:DelayedWorkQueue |
newScheduledThreadPool( int corePoolSize, ThreadFactory threadFactory) |
1.2 任务队列-DelayedWorkQueue
- 该队列的数据结构是优先级队列(依赖堆实现),当新来任务时将该task插入堆并根据优先级重新调整堆,保证优先级最高的task在fist index
- 执行任务时,获取fist index中的task,并保证等待够delay时间后再执行(当fist task执行后也需要重新调整堆)
2、newCachedThreadPool 缓存型线程池
- 无核心线程数,无非核心线程数,执行完闲置60s回收,任务队列为不存储元素的阻塞队列
- 适用于短期异步的小任务,或负载较轻的服务器
- 创建的最大线程数为Integer.MAX_VALUE,当添加任务的速度大于线程池处理任务的速度,可能会创建大量的线程,消耗资源,甚至导致OOM
2.1 构造方法
构造方法 | 参数 |
ExecutorService newCachedThreadPool() | 参数默认值 corePoolSize:0 maximumPoolSize:Integer.MAX_VALUE keepAliveTime:60L unit:TimeUnit.SECONDS workQueue:SynchronousQueue<Runnable> |
ExecutorService newCachedThreadPool(ThreadFactory threadFactory) |
2.2 任务队列-SynchronousQueue
- 队列是不存储元素缓存队列的,每次要进行offer操作时必须等待poll操作,否则不能继续添加元素
- 当前线程A执行offer操作将task添加到queue中,若没有另一个线程来消费该task,那线程A会一直阻塞直到另一个线程来消费该task
3、newFixedThreadPool
- 创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程
- 适用于限制当前线程数量的应用场景,适用于负载比较重的服务器
- 创建了一个无界队列LinkedBlockingQueuesize,是一个最大值为Integer.MAX_VALUE的线程阻塞队列,当添加任务的速度大于线程池处理任务的速度,可能会在队列堆积大量的请求,消耗很大的内存,甚至导致OOM
3.1 构造方法
构造方法 | 参数 |
ExecutorService newFixedThreadPool(int nThreads) | corePoolSize:nThreads maximumPoolSize:nThreads keepAliveTime:0L unit:TimeUnit.MILLISECONDS, workQueue:LinkedBlockingQueue<Runnable> threadFactory |
ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) |
3.2 任务队列-LinkedBlockingQueue<Runnable>
- 队列默认size=Integer.MAX_VALUE即是一个无界队列,底层实现是链表,当添加任务的速度大于线程池处理任务的速度,可能会在队列堆积大量的请求,消耗很大的内存,甚至导致OOM
- 读和写使用的是两个不同的锁,所以是读写分离的队列
4、SingleThreadExecutor
- 创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务,如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它
- 此线程池保证所有任务的执行顺序按照任务的提交顺序执行
4.1 构造方法
构造方法 | 参数 |
ExecutorService newSingleThreadExecutor() | corePoolSize:1 maximumPoolSize:1 keepAliveTime:0L unit:TimeUnit.MILLISECONDS, workQueue:LinkedBlockingQueue<Runnable> threadFactory |
ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) |
4.2 任务队列-LinkedBlockingQueue<Runnable>
- 队列默认size=Integer.MAX_VALUE即是一个无界队列,底层实现是链表,当添加任务的速度大于线程池处理任务的速度,可能会在队列堆积大量的请求,消耗很大的内存,甚至导致OOM
- 读和写使用的是两个不同的锁,所以是读写分离的队列
线程池拒绝策略:
实现java.util.concurrent.RejectedExecutionHandler接口
1,CallerRunsPolicy:当想提交任务的线程池还存活,就由提交task的当前线程来执行
2,AbortPolicy:丢弃任务并抛出RejectedExecutionException异常,(默认拒绝策略)
3,DiscardPolicy:丢弃任务但是不抛异常
4,DiscardOldestPolicy:当想提交任务的线程池还存活,就将丢弃队列最前面的任务,然后重新提交被拒绝的任务
对比
类型 | 池内线程数量 | 任务队列 | 特点 | 应用场景 |
newScheduledThreadPool | 核心线程:固定 非核心线程:无限制 | DelayedWorkQueue |
| 执行定时/周期性任务 |
newCachedThreadPool | 无限制 | SynchronousQueue |
| 执行数量多,耗时少的线程任务 |
newFixedThreadPool | 固定 | LinkedBlockingQueue |
| 控制线程的最大并发数 |
newSingleThreadExecutor | 1个 | LinkedBlockingQueue |
| 单线程 |