8 Executors的四种线程池浅析
- 「newFixedThreadPool」
- 指定核心线程数,队列是LinkedBlockingQueue无界阻塞队列,永远不可能拒绝任务;适合用在稳定且固定的并发场景,建议线程设置为CPU核数
- 「newCachedThreadPool」
- 核心池大小为0,线程池最大线程数为最大整型,任务提交先加入到阻塞队列中,非核心线程60s没任务执行则销毁,阻塞队列为SynchronousQueue。newCachedThreadPool会不断的创建新线程来执行任务,不建议用
- 「newScheduledThreadPool」
- ScheduledThreadPoolExecutor(STPE)其实是ThreadPoolExecutor的子类,可指定核心线程数,队列是STPE的内部类DelayedWorkQueue。「STPE的好处是 A 延时可执行任务,B 可执行带有返回值的任务」
- 「newSingleThreadExecutor」
- 和newFixedThreadPool构造方法一致,不过线程数被设置为1了。SingleThreadExecutor比new个线程的好处是;「线程运行时抛出异常的时候会有新的线程加入线程池完成接下来的任务;阻塞队列可以保证任务按FIFO执行」
9 如果优雅地关闭线程池
- 线程池的关闭,就要先关闭池中的线程,上文第三点有提,暴力强制性stop线程会导致同步数据的不一致,因此我们要调用interrupt关闭线程
- 而线程池提供了两个关闭方法,shutdownNow和shuwdown
- shutdownNow:线程池拒接收新任务,同时立马关闭线程池(执行中的会继续执行完),队列的任务不再执行,返回未执行任务List
- shuwdown:线程池拒接收新任务,同时等待线程池里的任务执行完毕后关闭线程池,代码和shutdownNow类似就不贴了
10 线程池为什么使用的是阻塞队列
先考虑下为啥线程池的线程不会被释放,它是怎么管理线程的生命周期的呢
可以看出,无任务执行时,线程池其实是利用阻塞队列的take方法挂起,从而维持核心线程的存活
11 线程池的worker继承AQS的意义
worker继承AQS的意义:A 禁止线程未开始就被中断;B 同步runWorker方法的处理逻辑
12 拒绝策略
- AbortPolicy「丢弃任务并抛出RejectedExecutionException异常」
- DiscardOldestPolicy「丢弃队列最前面的任务,然后重新提交被拒绝的任务」
- DiscardPolicy「丢弃任务,但是不抛出异常」
- CallerRunsPolicy
“A handler for rejected tasks that runs the rejected task directly in the calling thread of the {@code execute} method, unless the executor has been shut down, in which case the task is discarded.”
如果任务被拒绝了,则由「提交任务的线程」执行此任务
13 ForkJoinPool了解一波
![基础篇:高并发一瞥,线程和线程池的总结(下篇)-鸿蒙开发者社区 基础篇:高并发一瞥,线程和线程池的总结(下篇)-鸿蒙开发者社区](https://dl-harmonyos.51cto.com/images/202311/2800bc728b33dc7a06d743c3f8fa16a7af8f67.png)
ForkJoinPool和ThreadPoolExecutor不同,它适合执行可以分解子任务的任务,如树的遍历,归并排序等一些递归场景
![基础篇:高并发一瞥,线程和线程池的总结(下篇)-鸿蒙开发者社区 基础篇:高并发一瞥,线程和线程池的总结(下篇)-鸿蒙开发者社区](https://dl-harmonyos.51cto.com/images/202311/c8bce745736cb8db81385985b9687c8c0e0389.png)
![基础篇:高并发一瞥,线程和线程池的总结(下篇)-鸿蒙开发者社区 基础篇:高并发一瞥,线程和线程池的总结(下篇)-鸿蒙开发者社区](https://dl-harmonyos.51cto.com/images/202311/b9e6e893789f69a5c44934f30b2f4c23764d45.png)
- ForkJoinPool每个线程有一个对应的双端队列deque;当线程中的任务被fork分裂,分裂出来的子任务会放入线程自己的deque,减少线程的竞争
- work-stealing工作窃取算法
![基础篇:高并发一瞥,线程和线程池的总结(下篇)-鸿蒙开发者社区 基础篇:高并发一瞥,线程和线程池的总结(下篇)-鸿蒙开发者社区](https://dl-harmonyos.51cto.com/images/202311/b6d392321a1c7033636624c946e36101bb58af.png)
当线程执行完自己deque的任务,且其他线程deque还有多的任务,则会启动窃取策略,从其他线程deque队尾获取线程
- 使用RecursiveTask实现forkjoin流程demo
参考文章
- Java线程和操作系统线程的关系[1]
- 线程的3种实现方式[2]
- 如何优雅的关闭Java线程池[3]
- Java程序员必备的一些流程图[4]
- JDK提供的四种线程池[5]
- 7种阻塞队列相关整理[6]
- 六种常见的线程池含ForkJoinPool[7]
文章转载自公众号:潜行前行