概述
B. 无界队列:队列的存储空间无限(不考虑内存空间),例如LinkedBlockingQueue。使用这种队列的线程池,worker线程的个数达到corePoolSize之后不再增加,新的任务全部都存入队列,所以maximumPoolSize参数不会产生实质性的作用。这种队列适合任务之间无依赖关系的场景,也可以用于对突然增长的高并发请求进行平滑处理或削峰。
C. 有界队列:有空间大小限制的阻塞队列,例如ArrayBlockingQueue。使用这种队列的时候,队列大小及maximumPoolSize这两个参数是比较难调整的。你可以多观察CPU利用率、线程上下文切换消耗、吞吐量等指标,结合任务类型(是否容易阻塞)等来调整这两个参数。假如任务的IO操作较多,那么系统就有较多空余时间执行上下文切换,此时可以适当增加maximumPoolSize让线程多一些;如果任务计算量较多,则可以适当增大队列、减少线程数,腾出上下文切换时间给任务。一般而言,调小队列大小之后就应该调大一些maximumPoolSize,反之亦然。
2. 线程池的饱和处理策略
当线程池已关闭或者达到饱和状态(队列和线程数均达到上限)时,再有线程提交任务,就会触发饱和处理策略。有4种策略:
-
ThreadPoolExecutor.AbortPolicy(放弃执行,提交的线程一调用submit()就会接收到RejectedExecutionException异常);
-
ThreadPoolExecutor.CallerRunsPolicy(在提交的线程中执行,提交的线程自己来运行这个任务,此时异步操作降级成同步操作);
-
ThreadPoolExecutor.DiscardPolicy(丢弃,这个任务被静静的扔掉,没有反馈);
-
ThreadPoolExecutor.DiscardOldestPolicy(丢弃最老的任务,把队列头部的那个任务丢掉,然后再次尝试提交)。
注意:JDK给线程池提供的饱和策略是可以扩展的,一般以上4种策略够用了。
3. 线程池如何关闭
当线程池不再被变量引用且线程池中线程数等于0时,线程池将自动关闭(利用Object.finalize实现)。但是又因为默认情况下,线程池中对应corePoolSize的线程不会终止,所以线程池依然不能自动终止。可借助allowCoreThreadTimeOut(boolean)让核心worker线程空闲一段时间之后自动终止,这样线程池就可以自动关闭了。另外,也可以手动调用shutdown()来显式关闭线程池。还有一种比较暴力的关闭方式shutdownNow(),它除了不允许新任务再提交,还会中断正在执行任务的worker线程,让线程池立即关闭,所以可能导致数据丢失。shutdown()与shutdownNow()的区别与联系如下图所示,请耐心分析,应该好懂的(包括设置线程池关闭状态以禁止新任务提交、给worker发中断、丢弃任务队列等)。
最后
以上就是独特柜子为你收集整理的Java并发工具ThreadPoolExecutor线程池使用讲解2的全部内容,希望文章能够帮你解决Java并发工具ThreadPoolExecutor线程池使用讲解2所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复