在Executors下主要有5个静态方法:
1. Executors.newWorkStealingPool
- JDK8引入,创建持有足够线程的线程池支持给定的并行度,并通过使用多个队列减少竞争,此构造方法把CPU数量设置为默认的并行度
public ForkJoinPool(int parallelism,
ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler,
boolean asyncMode) {
this(checkParallelism(parallelism),
checkFactory(factory),
handler,
asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
"ForkJoinPool-" + nextPoolId() + "-worker-");
checkPermission();
}
2. Executors.newCacheThreadPool
- 这个线程池是一个没有核心线程数的,且最大线程数是Integer.MAX_VALUE,且使用的队列是SynchronousQueue,这个队列有点反人类,他不存储元素的阻塞队列,在创建元素的时候每一个put操作必须等待take操作,否则就不能添加元素 。这样我们就知道了因为没有核心线程数,所以刚来的任务我们都会进入到队列中,但是这个队列没有take也不会put,此时那就是说队列满了,然后就创建最大线程数。且设置的最大线程数在空闲状态下的存活时间为60秒。当有线程闲下来的时候,如果有新的任务来的时候就是用空闲线程,但是有可能出现瞬间来了大量的请求,此时就会无限创建线程直到Integer.MAX_VALUE个线程,很多机器应该在没有达到之前就会OOM了。创建一个线程就会分配堆,本地方法栈,java虚拟机栈等。所以就很容易就OOM了
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
3. Executors.newScheduledThreadPool
- 线程数最大到Integer.MAX_VALUE,与上面所说的一样都有可能会OOM,他是ScheduledExecutorService接口家族的实现类,支持定时及周期性任务执行。与newCacheThreadPool的区别就是不回收工作线程。从下面代码可以看出到最后也是使用了ThreadPoolExcutor这个类然定义了对应对参数。如设置了最大线程数的存活时间是0秒。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
4. Executors.newSingleThreadExecutor
- 创建一个单线程的的线程池,相当于单线程串行执行任务,保证按任务的提交顺序依次执行。这个线程池虽然不会因为线程创建过多而oom但是会因为阻塞到队列而最后产生oom,因为他使用的是LinkedBlockingQueue 看源码我们可知他的最大长度也是Integer.MAX_VALUE,所以大量任務的提交也会导致OOM。
源码:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
5. Executors.newFixedThreadPool
- 输入的参数即是固定的线程数,即是核心的线程数也是最大的线程数,不存在空闲线程
- 看下面的源码我们可知最大线程数和核心线程数是相等的,也就可说只有核心线程数,我们都知道如果核心线程数没有特定的配置的话核心线程数一旦创建就不会被回收的。但是我们可以看到他使用的也是LinkedBlockingQueue且默认的大小为Integer.MAX_VALUE,所以也会OOM。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}