摘要:代码如下是并发包中提供的,用来快速创建不同类型的线程池。线程池的正确创建方式其实,问题很好解决。总结最后,我们在使用线程池的时候,需要根据使用场景来自行选择。扩展对于一些耗时的任务,盲目选择线程池往往不是最佳方案。
JAVA 线程池的正确打开方式
摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.com/jasonGeng88/blog当前环境
jdk == 1.8
Executors 使用的隐患先来看一段代码,我们要创建一个固定线程池,假设固定线程数是4。代码如下:
Executors是JAVA并发包中提供的,用来快速创建不同类型的线程池。
是不是很简单,创建线程池只需一行代码。对于一些个人项目或临时性的项目,这样写确实没什么问题,而且开发速度很快。但在一些大型项目中,这种做法一般是禁止的。
WHY???
因为用Executors创建的线程池存在性能隐患,我们看一下源码就知道,用Executors创建线程池时,使用的队列是new LinkedBlockingQueue
当然,除了内存问题,它还存在一些其他的问题,在下面对线程池参数的介绍中会具体说明。
线程池的正确创建方式其实,问题很好解决。提供的简便方式有局限性,那我们自己new一个ThreadPoolExecutor,无非多写几行代码而已。
关于ThreadPoolExecutor的具体代码如下:
参数说明:corePoolSize:核心线程数;
maximumPoolSize:最大线程数,即线程池中允许存在的最大线程数;
keepAliveTime:线程存活时间,对于超过核心线程数的线程,当线程处理空闲状态下,且维持时间达到keepAliveTime时,线程将被销毁;
unit:keepAliveTime的时间单位
workQueue:工作队列,用于存在待执行的线程任务;
threadFactory:创建线程的工厂,用于标记区分不同线程池所创建出来的线程;
handler:当到达线程数上限或工作队列已满时的拒绝处理逻辑;
具体代码自定义threadFactory。除了可以自定义创建的线程名称,方便问题排查,在newThread(Runnable r)创建线程的方法中,还可以进行定制化设置,如为线程设置特定上下文等。
自定义RejectedExecutionHandler。记录异常信息,选择不同处理逻辑,有交由当前线程执行任务,有直接抛出异常,再或者等待后继续添加任务等。
创建自定义线程池
线程池内在处理逻辑我们通过一些例子,来观察一下其内部的处理逻辑。基于上述具体代码,我们已经创建了一个核心线程数4,最大线程数8,线程存活时间10s,工作队列最大容量为10的一个线程池。
初始化线程池:未添加线程任务
这时,线程池中不会创建任何线程,存活线程为0,工作队列为0.
未达核心线程数:添加4个线程任务
由于当前存活线程数 <= 核心线程数,所以会创建新的线程。即存活线程为4,工作队列为0.
核心线程数已满:添加第5个线程任务
若当前线程池中存在空闲线程,则交由该线程处理。即存活线程为4,工作队列为0.
若当前所有线程处理运行状态,加入工作队列。即存活线程为4,工作队列为1.(注意:此时工作队列中的任务不会被执行,直到有线程空闲后,才能被处理)
工作队列未满:假设添加的任务都是耗时操作(短时间不会结束),再添加9个耗时任务
即存活线程为4,工作队列为10.
工作队列已满 & 未达最大线程数:再添加4个任务
当工作队列已满,且不存在空闲线程,此时会创建额外线程来处理当前任务。此时存活线程为8,工作队列为10.
工作队列已满 & 且最大线程数已满:再添加1个任务
触发RejectedExecutionHandler,将当前任务交由自己设置的执行句柄进行处理。此时存活线程为8,工作队列为10.
当任务执行完后,没有新增的任务,临时扩充的线程(大于核心线程数的)将在10s(keepAliveTime)后被销毁。
总结最后,我们在使用线程池的时候,需要根据使用场景来自行选择。通过corePoolSize和maximumPoolSize的搭配,存活时间的选择,以及改变队列的实现方式,如:选择延迟队列,来实现定时任务的功能。并发包Executors中提供的一些方法确实好用,但我们仍需有保留地去使用,这样在项目中就不会挖太多的坑。
扩展对于一些耗时的IO任务,盲目选择线程池往往不是最佳方案。通过异步+单线程轮询,上层再配合上一个固定的线程池,效果可能更好。类似与Reactor模型中selector轮询处理
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/76315.html
摘要:你仅仅需要一个大小为数据库连接池,然后让剩下的业务线程都在队列里等待就可以了。你应该经常会看到一些用户量不是很大的应用中,为应付大约十来个的并发,却将数据库连接池设置成,的情况。请不要过度配置您的数据库连接池的大小。 文章翻译整理自: https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing欢迎关注个人微信公众...
摘要:你仅仅需要一个大小为数据库连接池,然后让剩下的业务线程都在队列里等待就可以了。你应该经常会看到一些用户量不是很大的应用中,为应付大约十来个的并发,却将数据库连接池设置成,的情况。请不要过度配置您的数据库连接池的大小。 文章翻译整理自: https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing欢迎关注个人微信公众...
摘要:最近项目中越来越多需要异步调用的地方,系统中虽有线程池管理,但还有可优化的空间,通过分享该文章,帮助大家了解线程池,同时学习使用线程池开启线程需要注意的地方。没错,上述方法创建的线程池就是。线程池就是程序中的装修公司,代劳各种脏活累活。 最近项目中越来越多需要异步调用的地方,系统中虽有线程池管理,但还有可优化的空间,通过分享该文章,帮助大家了解线程池,同时学习使用线程池开启线程需要注意...
摘要:本文主要内容为简单总结中线程池的相关信息。方法簇方法簇用于创建固定线程数的线程池。三种常见线程池的对比上文总结了工具类创建常见线程池的方法,现对三种线程池区别进行比较。 概述 线程可认为是操作系统可调度的最小的程序执行序列,一般作为进程的组成部分,同一进程中多个线程可共享该进程的资源(如内存等)。在单核处理器架构下,操作系统一般使用分时的方式实现多线程;在多核处理器架构下,多个线程能够...
阅读 1000·2022-07-19 10:19
阅读 1773·2021-09-02 15:15
阅读 993·2019-08-30 15:53
阅读 2632·2019-08-30 13:45
阅读 2619·2019-08-26 13:57
阅读 1962·2019-08-26 12:13
阅读 985·2019-08-26 10:55
阅读 524·2019-08-26 10:46