因为这样会导致内存不够用,内存耗尽,从而出现了OOM问题,所以阿里的java手册不建议使用Executors,建议使用ThreadPoolExecutor,这样创建就更加透明,而且让人更加熟悉线程池的过程,避免了创建大量的线程从而导致oom现象
错误代码演示:
package com.fan.mianshi100;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
public class Executor {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
// ThreadPoolExecutor
}
}
1.先看第一个newFixedThreadPool()的源码:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
根据我一开始写的程序,我只是限制了核心线程数,但是没有限制最大线程数,那么加之其使用的是无界队列 LinkedBlockingQueue,(其实这个也可以变为有界队列,只要给其参数,但是这个没给参数就是无界队列),那么程序就会创建无数的线程,从而使得内存不够用了,导致OOM问题
2.第二个是newSingleThreadExecutor的源码:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
这个跟第一个一样,也是使用了无界队列:LinkedBlockingQueue
3.第三个是newCachedThreadPool()的源码:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
这个是因为其线程最大设置为了Integer.MAX_VALUE,其最大值是 2,147,483,647,也就是2的32次方减1,这个数太大了,这么多的线程不发生OOM就怪事了
4.第四个是newScheduledThreadPool的源码:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
这个的问题也是将最大线程数设置成了Integer的最大数
5.第五个是newSingleThreadScheduledExecutor()的源码:
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
跟第四个的最终引用源码都一样,也都是将最大线程数设置成了Integer的最大数
正确应该使用ThreadPoolExecutor来通过线程池来创建线程,这样可以开发者控制线程池的参数,同时也让开发者更加熟悉线程池了
代码演示:
package com.fan.mianshi100;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
//通过ThreadPoolExecutor来创建自定义的线程池
public class ThreadPoolExample {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5,//核心线程数
18,//最大线程数
1,//非核心线程空闲存活时间
TimeUnit.MINUTES,//上一个的时间单位
new ArrayBlockingQueue<>(100));//任务队列,设置了容量了,
// 就不会存在无界队列,也不会产生oom问题了
//将任务提交到线程池
for (int i = 0; i < 20; i++) {
int taskNumber=i;
executor.execute(()->{
System.out.println("任务数"+taskNumber);
try {
Thread.sleep(3000); //模拟任务执行
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
}
//关闭线程池,如果我已经提交关闭线程池了,如果还有线程在执行
//如果60秒之内无论是否执行完成,都会关闭线程池,这是一种激进的关闭,看情况了
//具体情况具体分析
executor.shutdown();
try {
if (!executor.awaitTermination(60,TimeUnit.SECONDS)){
executor.shutdown();
}
} catch (InterruptedException e) {
executor.shutdown();
throw new RuntimeException(e);
}
System.out.println("所有任务结束!");
}
}