首先看源码中的一句注释:
A pool that is no longer referenced in a program and has no remaining
threads will be shutdown automatically.
如果程序中不再持有线程池的引用,并且线程池中没有线程时,线程池将会自动关闭。
线程池自动关闭的两个条件:1、线程池的引用不可达;2、线程池中没有线程;
这里对于条件2解释一下,线程池中没有线程是指线程池中的所有线程都已运行完自动消亡。
然而我们常用的FixedThreadPool的核心线程没有超时策略,所以并不会自动关闭。所以我们在使用fixedThrePool核心线程时需要适当调用Shutdown方法,防止内存溢出。
public class TExt {
public static void main(String[] args) {
ExecutorService eS = Executors.newFixedThreadPool(2);
MyThread myThread = new MyThread();
eS.submit(myThread);
eS.submit(myThread);
//eS.shutdown();
}
}
public class MyThread implements Runnable{
Object o=new Object();
@Override
public void run() {
synchronized (o){
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我执行了" + Thread.currentThread().getName() + " :" + i);
}
}
}
}
如上图所示代码运行,如果不调用Shutdown方法,程序将一直处于运行状态。
可以自动关闭的是CachedThreadPool 线程。
CachedThreadPool的线程keepAliveTime 默认为 60s ,核心线程数量为 0 ,所以不会有核心线程存活阻止线程池自动关闭。 详见 线程池之ThreadPoolExecutor构造 ,为了更快的模拟,构造后将 keepAliveTime 修改为1纳秒,相当于线程执行完马上会消亡,所以线程池可以被回收。实际开发中,如果CachedThreadPool 确实忘记关闭,在一定时间后是可以被回收的。
测试一下将上面的main方法代码修改为:
public class TExt {
public static void main(String[] args) {
ExecutorService eS = Executors.newCachedThreadPool();
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) eS;
// 为了更好的模拟,动态修改为1纳秒
threadPoolExecutor.setKeepAliveTime(1, TimeUnit.NANOSECONDS);
MyThread myThread = new MyThread();
eS.submit(myThread);
eS.submit(myThread);
//eS.shutdown();
}
}
因为动态修改了关闭时间为1纳秒,所以线程池结束后就直接关闭了。