1 Java线程池简介
Java1.5大师Doug Lea的作品。线程池能够对线程进行统一的分配,通过固定数量的线程来负责处理任务,避免了频繁的创建和销毁对象,使线程能够重复的利用,执行多个任务。
2 Java线程池的种类
线程工厂Executors实现的种类
种类 | 实现 | 基于的阻塞队列 | 说明 |
---|---|---|---|
固定大小线程池 | FixedThreadPool | LinkedBlockingQueue | 固定线程数量,任务队列无界 |
交付模式线程池 | CachedThreadPool | SynchronousQueue | 线程数量不限制,任务队列不存放数据 |
并行线程池 | WorkStealingPool | FIFO_QUEUE或LIFO_QUEUE | 线程数量不限制,分割任务执行 |
定时任务线程池 | ScheduledThreadPool | DelayedWorkQueue | 线程数量不限制,任务按时间优先级执行 |
单例固定线程池 | SingleThreadExecutor | LinkedBlockingQueue | 线程数量1个,任务按加入顺序执行 |
3 Java线程池的实现
3.1 阻塞队列
队列 | 实现 | 说明 |
---|---|---|
LinkedBlockingQueue | 基于链表和显示锁实现的队列 | 类似于LinkedList支持并发 |
SynchronousQueue | 基于双栈/双队列和显示锁实现的交付队列 | 基于双栈/双队列算法 |
DelayedWorkQueue | 基于优先级队列和显示锁实现的延迟队列 | 与优先级队列类似,由二叉堆算法实现 |
3.2 线程工厂Executors
线程池主体流程
3.2.1 CachedThreadPool
- 重用之前的线程(线程池中未被销毁的线程)
- 如果没有可用的线程,则创建一个新线程并添加到池中
- 池中线程默认为60s未使用就被终止和移除
- 长期闲置的池将会不消耗任何资源
交付(缓存)线程池的优势与弊病执行execute方法时,首先会先执行SynchronousQueue的offer方法提交任务,并查询线程池中是否有空闲线程来执行SynchronousQueue的poll方法来移除任务。如果有,则配对成功,将任务交给这个空闲线程。否则,配对失败,创建新的线程去处理任务;当线程池中的线程空闲时,会执行SynchronousQueue的poll方法等待执行SynchronousQueue中新提交的任务。若超过60s依然没有任务提交到SynchronousQueue,这个空闲线程就会终止;因为maximumPoolSize是无界的,所以提交任务的速度 > 线程池中线程处理任务的速度就要不断创建新线程;每次提交任务,都会立即有线程去处理,因此CachedThreadPool适用于处理大量、耗时少的任务。
优点: 任务立即执行,线程自动回收
缺点: 瞬间太高并发情况下会出现瞬间创建成千上万个线程,导致系统瘫痪
使用场景
OKHTTP 框架
3.2.2 FixedThreadPool
- 创建重用固定数量线程的线程池
- 当所有线程都处于活动状态时,如果提交了其他任务, 他们将在队列中等待一个线程可用
- 任务数量达到最大时,再加入会被拒绝执行
- 线程会一直存在,直到调用shutdown
FixedThreadPool线程池的优势与弊病FixedThreadPool只有核心线程,且数量固定,没有非核心线程。keepAliveTime设置为0L,代表多余的线程会被立即终止。因为不会产生多余的线程,所以keepAliveTime是无效的参数;任务队列采用了无界的阻塞队列LinkedBlockingQueue(容量默认为Integer.MAX_VALUE)。
优点: 线程固定数量相对可控
缺点: 高并发下的任务执行会变得缓慢,都会在队列中进行等待。
使用场景
Tomcat 工作线程
3.2.3 ScheduledThreadPool
- 设定延迟时间,定期执行
- 空闲线程会进行保留
当执行ScheduledThreadPoolExecutor的scheduleAtFixedRate或scheduleWithFixedDelay方法,会向DelayedWorkQueue添加一个实现RunnableScheduledFuture接口的任务包装类ScheduledFutureTask,并检查运行的线程是否达到核心线程数corePoolSize。如果没有就新建线程,并启动。但并非立即执行任务,而是去DelayedWorkQueue中取任务包装类ScheduledFutureTask,然后再去执行任务; 如果运行的线程达到了corePoolSize,就把任务添加到任务队列DelayedWorkQueue中;DelayedWorkQueue会将任务排序,先执行的任务放在队列的前面。 任务执行完后,ScheduledFutureTask中的变量time改为下次要执行的时间,并放回到DelayedWorkQueue中。
3.3 拒绝策略
策略 | 说明 |
---|---|
AbortPolicy | 当任务添加到线程池中被拒绝时,它将抛出RejectedExecutionException 异常。 |
CallerRunsPolicy | 当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。 |
DiscardOldestPolicy | 当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。 |
DiscardPolicy | 当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。 |
4 说明
参考资料
线程池之ScheduledThreadPool学习 blog.csdn.net/qq_36299025…
五种线程池的对比与使用
其他资料
Java优先级队列DelayedWorkQueue原理分析 www.jianshu.com/p/587901245…
SynchronousQueue原理详解-公平模式 www.cnblogs.com/dwlsxj/p/Th…
SynchronousQueue原理详解-非公平模式 www.cnblogs.com/dwlsxj/p/sy…