我试图实现一个函数,其中callables在规定的时间内完成或者操作超时。我曾希望ExecutorService.awaitTermination()
能做到这一点但却惊讶地发现它并没有。代码如下。运行永远不会完成。
public class Counter implements Callable<Void> {
public static void main(String[] args) throws InterruptedException {
final Map<String, Counter> map = new HashMap<>();
map.put("", new Counter());
final Map<String, Future<Void>> result = executeTasksInParallel(map);
final Future<Void> voidFuture = result.get("");
try {
voidFuture.get();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Void call() throws Exception {
for (long i = 0L; i < Long.MAX_VALUE; i++);
return null;
}
public static <K, V> Map<K, Future<V>> executeTasksInParallel(final Map<K, ? extends Callable<V>> callablesById) throws InterruptedException {
final Map<K, Future<V>> resultFuturesById = new HashMap<>();
final ExecutorService executorService = Executors.newFixedThreadPool(callablesById.size());
for (final Map.Entry<K, ? extends Callable<V>> callableByIdEntry : callablesById.entrySet()) {
final K id = callableByIdEntry.getKey();
final Callable<V> callable = callableByIdEntry.getValue();
final Future<V> resultFuture = executorService.submit(callable);
resultFuturesById.put(id, resultFuture);
}
executorService.shutdown();
executorService.awaitTermination(5L, TimeUnit.SECONDS);
return resultFuturesById;
}
}
我在这里遗漏了什么吗?谢谢!
更新:
我尝试用下面的替换try块内容来避免阻止Future.get(),但这并没有帮助
if (voidFuture.isDone()) {
voidFuture.get();
}
答案 0 :(得分:2)
shutdownNow()
,因为Joe C指定了...... call()
中的代码允许它,例如通过检查当前线程是否被干扰,它才会起作用。参见例如this question及其详细解答。如果通过抛出InterruptedException
(示例为Thread.sleep(...)
,Object.wait(...)
来调用(直接或间接)正确处理中断请求的方法,您偶尔可能会在循环中没有这种“协作”行为, Future.get(...)
,阻止对实现InterruptibleChannel的通道执行操作等。 编辑: ...如果没有抑制抛出的InterruptedException
。get()
时调用isDone()
(因为它在主线程上并非由executorService
管理)。最终的代码是
public class Counter implements Callable<Void> {
public static void main(String[] args) throws InterruptedException {
final Map<String, Counter> map = new HashMap<>();
map.put("", new Counter());
final Map<String, Future<Void>> result = executeTasksInParallel(map);
final Future<Void> voidFuture = result.get("");
try {
if (voidFuture.isDone()) {
voidFuture.get();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Void call() throws Exception {
for (long i = 0L; i < Long.MAX_VALUE; i++) {
if (Thread.currentThread().isInterrupted()) {
Thread.currentThread().interrupt(); // restore interrupted flag
return null;
}
/* or e.g. throw an exception */
}
return null;
}
public static <K, V> Map<K, Future<V>> executeTasksInParallel(
final Map<K, ? extends Callable<V>> callablesById)
throws InterruptedException {
final Map<K, Future<V>> resultFuturesById = new HashMap<>();
final ExecutorService executorService =
Executors.newFixedThreadPool(callablesById.size());
for (final Map.Entry<K, ? extends Callable<V>> callableByIdEntry : callablesById
.entrySet()) {
final K id = callableByIdEntry.getKey();
final Callable<V> callable = callableByIdEntry.getValue();
final Future<V> resultFuture = executorService.submit(callable);
resultFuturesById.put(id, resultFuture);
}
executorService.shutdown();
executorService.awaitTermination(5L, TimeUnit.SECONDS);
executorService.shutdownNow();
return resultFuturesById;
}
}
答案 1 :(得分:1)
awaitTermination()
并没有尝试杀死正在运行的任务。 awaitTermination()
完成后,您应该致电shutdownNow()
以尝试杀死仍然存在的内容。
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#shutdownNow()
答案 2 :(得分:0)
awaintTermination的文件:
阻止所有任务在关闭请求之后完成执行,或发生超时,或者当前线程被中断,以先发生者为准。
它将在5秒后完成,但生成的线程仍在工作且它不是守护程序线程,因此您的代码将继续工作,直到子线程终止。
voidFuture.get()
将阻止,直到返回。