ExecutorService.awaitTermination()永远不会超时

时间:2016-09-14 02:59:48

标签: java concurrency executorservice callable

我试图实现一个函数,其中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();
}

3 个答案:

答案 0 :(得分:2)

  1. 使用shutdownNow(),因为Joe C指定了......
  2. ...但只有call()中的代码允许它,例如通过检查当前线程是否被干扰,它才会起作用。参见例如this question及其详细解答。如果通过抛出InterruptedException(示例为Thread.sleep(...)Object.wait(...)来调用(直接或间接)正确处理中断请求的方法,您偶尔可能会在循环中没有这种“协作”行为, Future.get(...),阻止对实现InterruptibleChannel的通道执行操作等。 编辑: ...如果没有抑制抛出的InterruptedException
  3. 是的,只有在未来get()时调用isDone()(因为它在主线程上并非由executorService管理)。
  4. 最终的代码是

    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()将阻止,直到返回。