关闭ExecutorService的两个实例

时间:2015-12-28 19:19:27

标签: java multithreading executorservice shutdown

我需要在一种方法中正确关闭两个Executor Service实例。

这是我的简化代码:

ExecutorService executor1 = Executors.newSingleThreadExecutor();
ScheduledExecutorService executor2 = Executors.newSingleThreadScheduledExecutor();
// logic here
executor1.shutdown();
executor2.shutdown();
try {
    if (!executor1.awaitTermination(1, TimeUnit.SECONDS)) {
        executor1.shutdownNow();
    }
} catch (InterruptedException ex) {
    throw new IllegalStateException(ex);
}
try {
    if (!executor2.awaitTermination(1, TimeUnit.SECONDS)) {
        executor2.shutdownNow();
    }
} catch (InterruptedException ex) {
    throw new IllegalStateException(ex);
}

InterruptedException转换为IllegalStateException,因为我预计此处不会出现任何中断,这意味着我的申请会进入非法状态。

我在这个解决方案中看到一个缺陷 - 每当第一个执行者关闭时抛出异常,第二个执行器将无法正常关闭。这里应该采用什么方法?如何安全地关闭ExecutorService的两个实例?

我宁愿避免嵌套try-finally块,因为我可能需要添加第三个执行器服务,代码将变得无法管理。

1 个答案:

答案 0 :(得分:2)

至于类似的情况:

Apache Commons IO有closeQuietly()关闭流(或者更确切地说是任何Closeable),而忽略了关闭期间的任何异常。

public void shutdownQuietly(ExecutorService executor)
{
    try {
        if (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
            executor.shutdownNow();
        }
    } catch (InterruptedException ex) {
       /* IGNORE */
    }  
}

如果您需要这些例外,您可以尝试一些稍微恶劣的诡计:

class MultiExecutorShutdown
{
     private final List<InterrupedException> exceptions = new ArrayList<>();

     public void shutdown(ExecutorService service)
     {
         try {
             if (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
                executor.shutdownNow();
             }
         } catch (InterruptedException ex) {
             exceptions.add(ex);
         }
     }

     public Optional<InterruptedException> getLastException()
     {
         if (exceptions.isEmpty()) {
            return Optional.empty();
         } else {
             return exceptions.get(exceptions.size() - 1);
         }
     }

     public Optional<InterruptedException> getFirstException()
     {
         if (exceptions.isEmpty()) {
            return Optional.empty();
         } else {
             return exceptions.get(0);
         }
     }
}


[...]
MultiExecutorShutdown multiShutdown = new MultiExecutorShutdown();
multiShutdown.shutdown(executor1);
multiShutdown.shutdown(executor2);
multiShutdown.shutdown(executor3);

Optional<InterruptedException> exception = multiShutdown.getLastException();
// alternative:
// Optional<InterruptedException> exception = multiShutdown.getFirstException();

if (exception.isPresent()) {
   throw new IllegalStateException(exception.get());
}

如果您还需要失败的遗嘱执行人,您也可以修改MultiExecutorShutdown以保留(有序)地图ExecutorService -> Exception

您也可以将投掷推入MultiExecutorShutdown本身,使其更加实用。最后,整个事情可以 - 当然 - 被抽象出来,以便它需要一个功能,调用并记录抛出的任何异常。