
说到 Java 多线程就联想到 Thread、Runnable 等常用类,但是在实际项目中为了避免难以控制的线程创建,往往很少直接创建线程,都是创建线程池,提交任务到线程池执行。这点在阿里 Java 开发手册里也有提到。
线程池 ThreadPoolExecutor
类位于 Java 并发包下,为我们提供了管理线程池、任务提交、调度等功能。
ThreadPoolExecutor 创建
ThreadPoolExecutor
类提供了如下几个构造方法:
1 | // 使用默认的线程创建方式和默认的拒绝策略。 |
最终调用的还是参数最多的这个构造方法:
1 | public ThreadPoolExecutor( |
其中各参数含义是:
corePoolSize
核心线程数
maximumPoolSize
最大线程数
keepAliveTime
当线程池中线程数超过核心线程数时,空闲线程的存活时间。
unit
上述空闲时间的单位,可选:填、小时、分、秒。
workQueue
当线程池中线程超过核心线程数,再往线程池中提交任务,会存到该任务队列中。
threadFactory
线程创建工厂,默认使用的是:
DefaultThreadFactory
。handler
当线程池中线程数超过最大线程数时,会触发该拒绝策略,默认是:
AbortPolicy
,直接抛异常。
线程管理机制
可能有些人比较容易混淆 corePoolSize
,maximumPoolSize
,workQueue
之间的关系。这就涉及到线程池的线程管理机制。
可以通过如下流程图理解线程管理逻辑:
以一个简单例子验证上述流程:
1 | import java.util.concurrent.ArrayBlockingQueue; |
运行结果:
1 | 16:45:54.188 [pool-1-thread-1] INFO MyThread - Begin job >>> 0 |
可以看出:
最开始执行了 6 个线程的任务,因为最大线程数就是 6。
然后再提交的 8、9 号任务被拒绝了。
待 0 号线程执行完后,开始执行队列中的 3 号任务,然后 1 号线程执行完后,开始执行队列中的 4 号任务。
等待一段时间后,线程池中的线程数又缩小到了 3 个。
与上述流程图一致。
Executors
Executors
类提供了几种创建特定线程的静态方法:
1 | // 固定线程数的线程池,加上无限制的线程队列。 |
阿里开发手册提示:
线程池不允许使用
Executors
去创建,而应通过ThreadPoolExecutor
的方式,这样的处理方式让写同学更加明确线程池运行规则,避资源耗尽风险。
其实从上面举的几个创建线程的方法可以看出,无限制队列、最大线程数无线大等都有比较特殊的使用场景,还是使用 ThreadPoolExecutor
创建符合自身项目的线程池吧!
参考文章
https://segmentfault.com/a/1190000015368896
https://www.cnblogs.com/zedosu/p/6665306.html
https://www.cnblogs.com/wxd0108/p/5479442.html
https://www.runoob.com/java/java-multithreading.html