主要就是3大方法、7大参数和4种策略
三大方法
创建只有一个线程的线程池
Executors.newSingleThreadExecutor()
创建固定线程的线程池
Executors.newFixedThreadPool(5)
创建含有5个线程的线程池
创建可以伸缩的线程池
Executors.newCachedThreadPool()
使用线程池创建线程
executorService.execute(()->{
//方法体
});
注意
阿里巴巴手册规定不能使用Executors创建线程池,而是通过ThreadPoolExecutor
因为Executors返回的线程池对象有如下弊端
- FixedThreadPool和SingleThreadPool
允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量请求,导致OOM - CachedThreadPool和ScheduledThreadPool
允许创建的线程数量为Integer.MAX_VALUE,可能会创建大量线程,导致OOM
至于为什么,讲到七大参数再提
七大参数
进入三者的源码我们可以发现

其实三种方法都是调用了ThreadPoolExecutor类的构造方法来创建线程池,而唯一的区别就是三种方法填入的参数不同
接下来我们就来逐一解释一下这几个参数
public ThreadPoolExecutor(int corePoolSize, //线程池常驻核心线程数
int maximumPoolSize, //线程池能供容纳同时执行的最大线程数
long keepAliveTime, //多余空间线程存活时间
TimeUnit unit, //keepAliveTime的时间单位
BlockingQueue<Runnable> workQueue, //任务队列,被提交但尚未执行的任务
ThreadFactory threadFactory, //表示声场线程池中的工作线程的线程工厂
RejectedExecutionHandler handler) //拒绝策略,表示对列满了并且工作线程大于等于线程池的最大线程数时如何拒绝
-
corePoolSize:线程池中常驻核心线程数
-
maximumPoolSize:线程池能够容纳同时执行的最大线程数
-
keepAliveTime:多余的空闲线程存活时间
-
unit:keepAliveTime的时间单位
-
workQueue:任务队列,被提交但尚未执行的任务
-
threadFactory:表示生成线程池中的工作线程的线程工厂
-
handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何拒绝。
用银行举例子就是
- corePoolSize就是银行中长时间开启的柜台
- maximumPoolSize银行中暂时未开放,但是当等待的人多了,就会开放的柜台
- keepAliveTime就是当因为人多开启多余柜台后,当人数减少了,这个柜台用不到了,当这个柜台用不到多久就关闭
- workQueue就是在候客区等候的客人
- handler就是当银行柜台和候客区都满了的时候,如果再来了人怎么处理
这时候就可以解决上面三个方法的问题了
Executors.newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
我们可以看到
- 核心线程数为0
- 最大线程数时INT的最大值(21e)
这就是手册上所说的,可能会创建大量线程
四种拒绝策略

我们进入拒绝策略接口,可以看到四个实现类,这就是我们的四种拒绝策略
CallerRunsPolicy
当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。
相当于哪来的去哪里,相当于从公司来的银行,银行让这个人回到公司去办理,也就是mian线程进入满了的话,main线程处理
AbortPolicy
丢弃任务,并抛出拒绝执行 RejectedExecutionException 异常信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行。
相当于银行满了,还有人进来,不处理这个人,并且抛出异常
DiscardPolicy
直接丢弃,其他啥都没有
DiscardOldestPolicy
当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入
与上一个不同的是,当队列满了以后,尝试去和最早的竞争,也不会抛出异常,只不过在抛弃之前多了一次尝试
使用线程池的好处
- 线程的复用
线程的创建和小会对系统来说是巨大的开销,而用线程池管理线程能大大减少这种不易要的开销 - 控制线程并发数
控制线程池中线程的并发数,可以防治大量线程争夺CPU资源造成拥塞
可以控制线程的最大并发数 - 可以对线程进行管理
线程池可以提供定时定期使用
最大线程应该如何定义
主要有两种方法定义
- CPU密集型
CPU有多少个线程最大线程就是几
注意不要用常量,而是用下面的方法获取核数,因为相同的程序在不同的服务器上可能核数不同
System.out.println(Runtime.getRuntime().availableProcessors()); //输出服务器的核数
- IO密集型
判断程序中十分耗IO的线程,线程数只需要大于这些线程的个数就可以了
参考文章
线程池七大参数
【狂神说Java】JUC并发编程最新版通俗易懂
线程池-四种拒绝策略总结
使用线程池的好处
本文详细介绍了Java线程池的创建方法,包括`Executors`的四种类型及其潜在问题,强调了阿里巴巴开发手册推荐使用`ThreadPoolExecutor`直接创建线程池的原因。线程池的七大参数如核心线程数、最大线程数、存活时间等被详细解析,以及四种拒绝策略的适用场景。最后讨论了线程池的优势,如线程复用、控制并发数,并给出了最大线程数的合理定义方法。
&spm=1001.2101.3001.5002&articleId=123082178&d=1&t=3&u=c19a007abe98466d8630df8c7c244b04)
2309

被折叠的 条评论
为什么被折叠?



