2015-12-28 2 views
2

Мне нужно правильно закрыть два экземпляра службы-исполнителя одним способом.Завершение работы двух экземпляров ExecutorService

Вот мой упрощенный код:

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, так как мне, возможно, потребуется добавить третий сервис-исполнителя, и код станет неуправляемым.

+0

Является ли это таким же, как: http://stackoverflow.com/questions/25330464/running-multiple-thread-pools-executorservice-together? –

+0

@YacoZaragoza не очень - здесь мой пример кода упрощен, но мне нужны два отдельных сервиса-исполнителя, так как один из них нормальный, а второй - служба-исполнитель. –

+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, что делает его еще более удобным для использования. И, наконец, все это может быть, конечно, абстрагировано, так что оно требует функциональности, вызывает это и записывает любые выброшенные исключения.

+0

Если каждый из трех «ExecutorServices» выдает исключение, вы не сможете получить к ним доступ только с использованием методов первого и последнего доступа. – harpun

+0

@harpun Исправить. Реализация должна быть адаптирована к конкретному варианту использования. Если вам нужны все три исключения, добавьте соответствующий метод доступа. Вы даже можете использовать стратегический паттерн, чтобы сделать разрешаемое приложение подключаемым, но это может быть слишком сложным решением. – dhke

Смежные вопросы