什么是线程池?
内存中的一块空间,空间里存放着已经实例化好的线程对象.
当需要使用线程时直接从线程池中去取,当代码中线程执行结束或者销毁时,把线程重新放入线程池,而不是让它处于死亡状态.
优点
降低系统资源消耗。通过重用线程对象,降低因为新建和销毁线程产生的系统消耗。
提高系统响应速度。直接从内存中获取线程对象,比新建线程更快。
提供线程可管理性。通过对线程池中线程数量的限制,避免无限创建线程导致的内存溢出或CPU资源耗尽等问题。
缺点
默认情况下,无论是否需要使用线程对象,线程池中都有一些线程对象,也就是说会占用一定内存。
Executor关系图
自定义线程池
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数总结:
- corePoolSize: 核心线程数大小
- maximumPoolSize:最大线程数大小(线程池中一共存在多少个线程)
- keepAliveSize:线程最大空闲时间
- unit;时间单位
- workQueue:任务队列类型
- threadFactory:线程工厂
- handler:拒绝策略
创建线程总结:
当线程数小于核心线程数时,创建线程, 直到达到指定的核心线程数。
当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列(指的是有存储空间的队列,SynchronousQueue没有存储空间)。
当线程数大于等于核心线程数,且任务队列已满 。
i. 若线程数小于最大线程数且最大线程数是非零,创建临时线程, 直到达到最大线程数 。
注意:
如果工作队列满了,.但是核心线程有空闲的线程时,那么核心线程就会利用起来,把队列的第一个任务交给核心线程去处理,新的任务去工作队列缓存,
ii. 线程数等于最大线程数,触发拒绝策略,抛出异常
handler线程池拒绝策略
只有当任务队列已满,且线程数量已经达到maximunPoolSize才会触发拒绝策略。
1.AbortPolicy:默认策略,新任务提交直接抛出RejectedExecutionException,由调用者捕获
2.DisCardPolicy:丢弃新的任务,且不抛出异常.
3.DisCardOldestPolicy:调用poll()方法丢弃队列头的任务,然后提交新的任务
4.CallerRunsPolicy:由调用该任务的线程处理,线程池不参与,只要线程池不关闭,该任务一直在调用者的线程中.
Executors
Executors可以帮助快速实例化特定类型的线程池对象, Executors属于一个工具类, 返回值都是ExecutorService接口的实现类, 底层都是调用ThreadPoolExecutor()
1 SingleThreadExecutor()
- 构造方法参数:
- corePoolSize和maximumPoolSize: 1
- keepAliveTime: 0秒
- unit: 微妙
- workQueue: LinkedBlockingQueue
- 效果总结:
- 它只会创建一条工作线程处理任务;
- 采用的阻塞队列为LinkedBlockingQueue, 底层为单向链表。
2.newFixedThreadPool(int)
构造方法参数:
- corePoolSize和maximumPoolSize: nTheads
- keepAliveTime: 0秒
- unit: 毫秒
- workQueue: LinkedBlockingQueue
效果总结:
- 它是一种固定大小的线程池;
- corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads;
- keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉;但这里keepAliveTime无效;
- 阻塞队列采用了LinkedBlockingQueue, 底层为链表;
- 实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。
3.newCachedThreadPool():缓存线程池
构造方法参数:
- corePoolSize: 0
- maximumPoolSize: Integer的最大值
- keepAliveTime: 60秒
- unit: 秒
- workQueue:SynchronousQueue
效果总结:
它是一个可以无限扩大的线程池;
它比较适合处理执行时间比较小的任务;
corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大;
keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死;
采用SynchronousQueue(同步队列)装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。
4.newScheduledThreadPool()
构造方法参数:
- corePoolSize: corePoolize
- maximumPoolSize: Integer的最大值
- keepAliveTime: 10L
- unit: 毫秒
- workQueue:DeplayedWorkQueue
效果总结:
它采用DelayQueue存储等待的任务
它会根据time的先后时间排序,若time相同则根据sequenceNumber排序;
DelayQueue队列:
底层使用数组实现, 初始容量为16, 超过16个任务, 数组扩容, 每次扩容为之前的1.5倍
工作线程会从DelayQueue取已经到期的任务去执行;
执行后也可以将任务重新定时, 放入队列中;
支持定时, 周期性执行。