代码之家  ›  专栏  ›  技术社区  ›  Michal Kordas FrantiÅ¡ek Hartman

关闭ExecutorService的两个实例

  •  3
  • Michal Kordas FrantiÅ¡ek Hartman  · 技术社区  · 9 年前

    我需要在一个方法中正确关闭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 回复  |  直到 9 年前
        1
  •  2
  •   dhke    9 年前

    对于类似情况:

    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 .

    你也可以把掷球 多执行器关闭 使其更加可用。最后,整个过程可以——当然——被抽象,这样它就可以接受函数,调用函数并记录抛出的任何异常。