此问题与我之前的问题有关:Why the speed of a Java process inside multiple loops slows down as it goes?
为了找到问题的问题,我仔细查看了我的代码,发现我的应用程序中的一些执行程序没有终止,因为我正在学习如何使用执行程序,我复制了一些在线示例代码并在我的应用程序中使用它们,我不确定我是否正确使用它们。
以下两种使用执行程序的方法之间的区别是什么?
[1]
Executor executor=Executors.newFixedThreadPool(30);
CountDownLatch doneSignal=new CountDownLatch(280);
for (int N=0;N<280;N++)
{
...
executor.execute(new SampleCountRunner(doneSignal,...));
}
try { doneSignal.await(); }
catch (Exception e) { e.printStackTrace(); }
[2]
ExecutorService executor=Executors.newFixedThreadPool(30);
for (int i=0;i<60;i++)
{
...
executor.execute(new xyzRunner(...));
}
executor.shutdown();
while (!executor.isTerminated()) { }
在第一个完成之后,我觉得执行程序仍然有一个活动的线程池在运行并等待更多任务,它们会消耗CPU时间和内存。
第二个将在shutdown()方法运行后终止池中的所有活动线程,并且所有先前活动的线程在该点之后将不再占用CPU时间或内存。
所以我的问题是:
[1]我说错了吗?
[2]如何在第一种情况下终止线程池? Executor没有“executor.shutdown()”
编辑:
问题解决了,我将[1]中的Executor更改为ExecutorService,并添加了:
executor.shutdown();
while (!executor.isTerminated()) { }
现在,当我的程序结束时,它将不再有很多线程处于活动状态。
答案 0 :(得分:3)
在第一个完成之后,我觉得执行程序仍然有一个活动的线程池在运行并等待更多任务,它们会消耗CPU时间和内存。
不完全是。在第一种方法中,在任务完成之后(由锁存器发出信号),执行程序绝对不会关闭 - 但执行程序中的线程不会消耗cpu(它们消耗了其结构所需的最小内存)。
在这种方法中 - 您可以明确控制知道任务的完成时间和方式。您可以知道任务是成功还是失败,并且可以根据需要决定重新提交任务。
第二个将在shutdown()方法运行后终止池中的所有活动线程,并且所有先前活动的线程在该点之后不再需要CPU时间或内存。
同样,不完全一样。在这种方法中,ExecutorService在调用shutdown()
后不会立即关闭。它等待已经提交的任务完成,但是在这里你不直接知道这些任务是否成功完成或者它们是否失败(通过抛出一些Exception
)。
在完成已提交的任务之前 - 您的isShutDown()
将执行紧急循环(它会使cpu达到接近100%)。
答案 1 :(得分:1)
一般来说,线程池(ExecutorService)通常不会被定期创建/销毁。相反,它们应该是长期存在的(可能是应用程序的整个生命周期),以避免线程创建/销毁的(重大)开销。
如果您想提交任务列表并等待所有任务完成,请使用ExecutorService.invokeAll()而不是尝试通过倒计时锁定跟踪完成。
ExecutorService接口提供了两种关闭机制:shutdown和shutdownNow。第一个简单地停止接受新的工作,并将停止当前正在执行的线程,并且已完成已完成的工作。第二个将尝试中断正在进行的所有工作,甚至不会对已经提交但尚未开始的工作起作用。