什么是线程池
就是把线程用一个队列管理起来(池子), 需要用的时候从这里拿, 用完放回来, 避免野蛮的新起线程执行任务
为什么要线程池
1. 避免重复开销
线程的创建
和销毁
是比较消耗资源的, 特别是如果执行时间还比创建
和销毁
时间短, 就更加不划算了, 所以通过线程池来管理线程, 免去频繁的创建
和销毁
带来的额外花销
2. 防止线程爆发
暴力的直接开线程执行任务, 如果这种代码多了, 很多线程同时创建执行, 很容易造成资源不够用, 从而导致一些异常发生
几种线程池创建的区别
Executors
中就有一些线程池模板(也可以自己通过ThreadPoolExecutor
来创建)
-
FixedThreadPool : 定长线程池, 使用
LinkedBlockingQueue
堆集的运行任务顺序执行 -
SingleThreadExecutor: 相当于FixedThreadPool的单线程版本
-
CachedThreadPool: 缓存线程池, 线程最大数为整形最大值, 过期时间60秒, 无核心线程, 使用同步队列
SynchronousQueue
(无空闲线程, 直接创建线程执行) -
ScheduledThreadPool: 使用延时队列
DelayQueue
, 支持定时任务, 需要进来的执行任务实现Delayed接口
-
SingleThreadScheduledExecutor:
ScheduledThreadPool
的单线程版
也可以自定义线程池
部分名词解释
- corePoolSize: 核心线程数量, 默认是不会关闭的, 但如果指定了
allowCoreThreadTimeOut=true
, 则会根据keepAliveTime
将空闲核心线程回收 - maximumPoolSize: 最大线程数, 线程池中最多可以开启的线程数, 会根据
keepAliveTime
进行空闲线程回收 - keepAliveTime: 最大空闲时间, 超过该时间的
空闲非核心线程
会被销毁(allowCoreThreadTimeOut=true
时, 核心线程也会被销毁) - unit:
keepAliveTime
的时间单位(具体枚举值下面列出) - workQueue: 任务队列, 存放需要自行的的任务(具体4中队列类型下面列出)
- threadFactory: 线程创建工厂, 可以自定义线程名称什么的(一般很少用)
- handler: 异常(一般很少用)
时间单位
- NANOSECONDS : 1微毫秒 = 1微秒 / 1000
- MICROSECONDS : 1微秒 = 1毫秒 / 1000
- MILLISECONDS : 1毫秒 = 1秒 /1000
- SECONDS : 秒
- MINUTES : 分
- HOURS : 小时
- DAYS : 天
队列类型
-
SynchronousQueue: 这个队列接收到任务的时候,会直接提交给线程处理,而不保留它,如果所有线程都在工作怎么办?那就新建一个线程来处理这个任务!所以为了保证不出现<线程数达到了
maximumPoolSize
而不能新建线程>的错误,使用这个类型队列的时候,maximumPoolSize
一般指定成Integer.MAX_VALUE
,即整型最大数 -
LinkedBlockingQueue: 这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了
maximumPoolSize
的设定失效,因为总线程数永远不会超过corePoolSize
-
ArrayBlockingQueue:可以限定队列的长度,接收到任务的时候,如果没有达到
corePoolSize
的值,则新建线程(核心线程)执行任务,如果达到了,则入队等候,如果队列已满,则新建线程(非核心线程)执行任务,又如果总线程数到了maximumPoolSize
,并且队列也满了,则发生错误 -
DelayQueue: 队列内元素必须实现
Delayed接口
,这就意味着你传进去的任务必须先实现Delayed接口
。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务