使用Executor框架的Callable接口:程序为何在call方法返回后仍不退出?
为什么Callable任务完成后程序无法退出?
嘿,这个问题我之前也踩过坑!你看,代码里ftask.get()确实会等Callable执行完拿到结果,也打印了"main over",但程序就是卡在那儿不肯退出对吧?
问题根源
你用Executors.newFixedThreadPool(5)创建的线程池,里面的工作线程默认是非守护线程。JVM的运行规则是:只有当所有非守护线程都结束时,JVM才会终止退出。而线程池的这些工作线程,在任务完成后不会自动销毁,会一直处于等待状态,等着接收新的任务——这就导致它们一直占着资源,JVM没法正常退出。
解决办法
有两个简单的方式可以搞定这个问题:
1. 手动调用shutdown()关闭线程池
在你确认所有任务都执行完成后,主动告诉线程池停止接受新任务,并逐步关闭现有线程。修改后的代码如下:
public static void main(String[] args) throws Exception { ExecutorService pool = Executors.newFixedThreadPool(5); Future<String> ftask = pool.submit(new CallableExample()); System.out.println("getting result"); System.out.println("----" + ftask.get()); System.out.println("main over"); // 关闭线程池,让JVM可以正常退出 pool.shutdown(); }
如果你需要立刻终止所有线程(哪怕还有任务没做完),可以用pool.shutdownNow(),不过一般shutdown()就足够了,它会等所有已提交的任务执行完再关闭。
2. 使用try-with-resources自动关闭(推荐)
从Java 7开始,ExecutorService实现了AutoCloseable接口,所以可以用try-with-resources语法,这样代码块结束时会自动调用shutdown(),不用手动写关闭代码,更简洁安全:
public static void main(String[] args) throws Exception { try (ExecutorService pool = Executors.newFixedThreadPool(5)) { Future<String> ftask = pool.submit(new CallableExample()); System.out.println("getting result"); System.out.println("----" + ftask.get()); System.out.println("main over"); } // 这里会自动执行pool.shutdown() }
额外说明
如果你好奇的话,可以用jconsole或者jstack工具看看程序运行时的线程状态,会发现线程池里的几个线程状态是WAITING (parking),它们就是导致程序没法退出的“元凶”——只要把线程池关闭,这些线程就会被终止,JVM也就正常退出了。
内容的提问来源于stack exchange,提问作者Uzair
相关产品推荐
相关产品推荐

