线程池使用
# Executors四大线程池
Exeutors类的==静态工厂==提供了常用的线程池
直接通过 Exeutors.方法名调用(静态方法)
静态方法 | 解释 |
---|---|
newCachedThreadPool | 可缓存的线程池,可创建任意大小的线程数,只要不超出JVM方法区(本地内存)的大小即可。60s会回收部分空闲线程 |
newFixedThreadPool | 定长线程池,大小固定且不能更改。可控制线程最大并发数,超出的线程会在队列中等待 |
newScheduledThreadPool | 定时及周期性任务执行线程任务 |
newSingleThreadExecutor | 单线程的线程池。单线程串型执行所有任务, 如果产生了异常,会有新的线程来替代,保证所有任务按序执行 |
- CachedThreadPool:初始核心线程数量为0,最大线程数量为Integer.MAX_VALUE,线程空闲时存活时间为60秒,并且它的阻塞队列为SynchronousQueue,它的初始长度为0,这会导致任务每次进来都会创建线程来执行,在线程空闲时,存活时间到了又会释放线程资源
- FixedThreadPool:线程池线程数量固定,即
corePoolSize
和maximumPoolSize
数量一样 - SingleThreadPool:单个线程的线程池
- ScheduledThreadPool:创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer
# 为什么不建议使用Executors
使用 ThreadPoolExecutor
的构造函数声明线程池
线程池必须手动通过 ThreadPoolExecutor
的构造函数来声明,避免使用Executors
类的 newFixedThreadPool
和 newCachedThreadPool
,因为可能会有 OOM 的风险。
答:原因如下
1. 只有使用有界队列,才能控制线程创建数量
**2. ThreadPoolExecutor能根据业务场景来灵活配置。**实际使用中需要根据自己机器的性能、业务场景来手动配置线程池的参数比如核心线程数、使用的任务队列、饱和策略等等
3. 应该显示地给我们的线程池命名,这样有助于定位问题
【源码查看】
// FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
// SingleThreadPool
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
// CachedThreadPool
public static ExecutorService newCachedThreadPool() {
// 允许创建线程数为Integer.MAX_VALUE
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
// ScheduledThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize) {
// 允许创建线程数为Integer.MAX_VALUE
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
// 无阶阻塞队列,使用一个有界队列,以防因队列过大而导致的内存溢出问题
public LinkedBlockingQueue() {
// 允许队列长度最大为Integer.MAX_VALUE
this(Integer.MAX_VALUE);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
从JDK源码可看出,Executors工具类无非是把一些特定参数进行了封装,并提供一些方法供我们调用而已,我们并不能灵活地填写参数,策略过于简单,不够友好。
CachedThreadPool和ScheduledThreadPool最大线程数为Integer.MAX_VALUE,如果线程无限地创建,会造成OOM异常。
LinkedBlockingQueue基于链表的FIFO队列,是无界的,默认大小是Integer.MAX_VALUE,因此FixedThreadPool和SingleThreadPool的阻塞队列长度为Integer.MAX_VALUE,如果此时队列被无限地堆积任务,会造成OOM异常。
编辑 (opens new window)
上次更新: 2021/06/27, 10:49:09