概念
管理一组线程的对象
作用
线程的创建和销毁需要消耗相当的资源,利用线程池可以提高创建线程的速度,并且线程可以被重复利用
创建
ThreadPoolExecutor
参数
int corePoolSize
- 核心线程数量
int maximumPoolSize
- 线程池的最大线程数(核心线程+非核心线程)
long keepAliveTime
- 非核心线程的存活时间
TimeUnit unit
BlockingQueue
workQueue - 存放任务的阻塞队列
ThreadFactory threadFactory
RejectedExecutionHandler handler
- 线程池饱和如何处理
执行
流程
核心线程
阻塞队列
线程池
- Handler
拒绝策略
线程池满了之后,再提交任务如何处理的问题
- Abort(直接抛异常)
- Discard(忽略新提交的任务)
- DiscardOldest(移除阻塞队列最旧的)
- CallerRun(交给线程池调用者处理)
异常处理
线程池内发生异常悄无声息,可能无法感知,需要主动去处理
- 直接在任务内部try+catch
- 用try+catch包裹future.submit
- 为工作线程设置UncaughtExceptionHandler
- 覆写线程池的AfterExcute方法
线程池的工作队列
阻塞队列,类似经典的IPC问题:生产-消费者问题,一个线程消耗,一个线程生产,在适当的时候需要阻塞线程
ArrayBlockingQueue
- 用数组实现
- FIFO
- 容量无法改变
LinkedBlockingQueue
- 用链表实现
- 可设置大小,默认Integer.MAX_VALUE
- FixedThreadPool采用这种阻塞队列
DelayQueue
- 根据指定的时间(1st)和进入队列的时间(2nd)排序
- ScheduledThreadPool采用这种阻塞队列
PriorityBlockingQueue
SynchronousQueue
- 内部只能包含一个元素,插入元素的线程被阻塞,直到另一个线程获取了队列中的元素,反之亦然
- CachedThreadPool采用这种阻塞队列
常用线程池
FixedThreadPool
特点
核心线程数和最大线程数相等
keepAliveTime=0
使用LinkedBlockingQueue(无界)
使用无界队列可能会使内存占用飙升,最终OOM
流程
- 核心线程–>阻塞队列–>OOM
使用场景
- 适合执行长期的,CPU密集型任务
CachedThreadPool
特点
核心线程数为0,最大线程数Integer.MAX_VALUE
都是打工仔,没有一个有编制
使用SynchronousQueue
非核心线程存活时间60s
流程
- 阻塞队列–>非核心线程–>非核心线程的销毁
使用场景
- 并发执行大量短期的小任务
SingleThreadExecutor
特点
- 只有一个核心线程
- 使用LinkedBlockingQueue(无界)
流程
- 一个线程日以继夜,笔耕不辍
使用场景
- 串行执行的任务
ScheduledThreadPool
特点
- 使用DelayQueue作为阻塞队列
- 没有非核心线程
- 可以设置周期和延迟
流程
- DelayQueue–>核心线程–>DelayQueue
使用场景
- 周期性的任务