我有这种奇怪的行为。我的程序挂起了,尽管我正在设置强制终止它的时间。任何人都可以指出这种奇怪的行为可能是什么?
这是我启动线程的代码
protected void pendingTaskStarter() throws Exception {
ExecutorService service = Executors.newFixedThreadPool(maxThreadNum);
ArrayList<Future<Runnable>> futures = new ArrayList<Future<Runnable>>();
System.out.println("max thread num: " + maxThreadNum);
for(int i=0;i<maxThreadNum;i++){
Thread t = new PendingTaskConsumer();
Future<?> f=service.submit(t);
futures.add((Future<Runnable>) f);
}
for (Future<?> future:futures) {
future.get(5l,TimeUnit.MINUTES); // maximum thread's life is 5min (5l <-- 5 in long )
}
service.shutdownNow();
}
我100%确定我的程序根据PendingTaskConsumer
类中的输出在PendingTaskConsumer
类中的某个位置挂起。
无论如何,PendingTaskConsumer中的代码应该是无关紧要的,因为线程应该被强制终止。 我的问题是下面一行中没有按预期做的那些情节。
future.get(5l,TimeUnit.MINUTES);
该程序正在Linux(Ubuntu)
并使用openjdk-7-jdk backage ( version 1.7)
答案 0 :(得分:1)
嗯......似乎缺少适当的异常处理。
/**
* Waits if necessary for at most the given time for the computation
* to complete, and then retrieves its result, if available.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
* @throws **TimeoutException if the wait timed out**
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
如果您对future.get(5l,TimeUnit.MINUTES);
的来电过期,则会抛出Exception
而您的service
永远不会关闭。
所以(可以假设)其内部线程仍在运行,至少是执行长时间运行任务的线程。看到这些是非守护进程线程(您必须自定义执行程序的ThreadFactory
),这些挂起的线程会阻止JVM关闭。
如果您希望强行终止任务,您可以:
Thread.isInterrupted()
,并在它看到变为真时退出。 (shutdownNow
的实际效果是设置executor
的线程的中断标志)但无论如何,我要先将executor
关闭,或者放在finally
条款中。
答案 1 :(得分:1)
正如@GPI在他/她的回答中已经说明的那样,如果您的任务没有通过Thread.interrupt()
来回应线程中断,则取消将无法正常工作。请参阅Oracle: The Java™ Tutorials - Concurrency - Interrupts或Java Executors: how can I stop submitted tasks?。
但是即使你的任务没有在线程被中断时立即停止(=设置了中断标志),你也可以超时你的方法。不要通过调用get()
的每个Future
方法来听取任务完成情况!这并不是必要的,因为你对他们的结果并不感兴趣。只需关闭ExecutorService
并等待其终止。
protected void pendingTaskStarter() throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(maxThreadNum);
for (int i = 0; i < maxThreadNum; i++) {
service.submit(new PendingTaskConsumer());
}
// Shutdown service.
// This will continue to process already submitted tasks.
service.shutdown();
try {
// wait at least 5 minutes for the tasks to complete
if (!service.awaitTermination(5, TimeUnit.MINUTES)) {
// still not done yet -> force shutdown
// this will interrupt currently running tasks.
service.shutdownNow();
}
} catch (InterruptedException ex) {
// someone interrupted this thread. Shutdown tasks immediately
service.shutdownNow();
// propagate exception
throw ex;
}
}
那么这里会发生什么?
shutdown()
上调用ExecutorService
。请注意,该服务将continue to execute already submitted tasks, but it will not accept new tasks。awaitTermination
,超时时间为5分钟。如果此方法返回true
,这意味着服务已在时间内终止,一切正常,我们就完成了。但如果它在5分钟后返回false
,则意味着该服务仍在运行,因为有些任务需要更多时间才能完成。shutdownNow()
立即关闭服务。请注意,此方法不会阻止!它只是尝试取消所有正在运行的任务,通常是通过中断当前正在执行它们的线程。 这正是您的任务应该正确响应线程中断的原因!如果他们不这样做,中断线程将完全没有效果! shutdownNow
是否成功 - 我们已经完成,不要再等了。因此,可能仍然存在一些正在运行的任务,因为它们不会在线程中断时做出反应(通常是因为任务要么没有正确实现,要么是故意无意中执行)。但我们根本不在乎。awaitTermination
中等待时调用我们方法的线程时,会抛出InterruptedException
。我们通过关闭服务并重新抛出异常来处理它!这是一件好事,使我们的方法成为一个可以自行取消的长期运行操作!