2016-09-14 2 views
0

Я пытаюсь реализовать функцию, в которой либо вызывающие абоненты заканчиваются в указанное время, либо время выполнения операции. Я надеялся, что ExecutorService.awaitTermination() сделает это, но был удивлен, увидев, что это не так. Код ниже. Запуск никогда не завершается.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; 
    } 
} 

Я что-то пропустил? Благодаря!

UPDATE:

Я пытался заменить содержимое попробовать блок с ниже, чтобы избежать Future.get() от блокировки, но это не помогло ни

if (voidFuture.isDone()) { 
    voidFuture.get(); 
} 
+0

ума? – mindreader

ответ

2
  1. Используйте shutdownNow(), как указал Джо C ...
  2. ... Но это будет работать только если ваш код в call() это позволяет, например, проверяя, если текущий поток будучи прерванным. См. this question и его ответы для деталей. Иногда вы можете обойтись без этого «кооперативного» поведения в своем цикле, если он вызывает (прямо или косвенно) методы, которые обрабатывают запросы прерываний должным образом, бросая InterruptedException (примеры: Thread.sleep(...), Object.wait(...), Future.get(...), блокирующие операции на канале, который реализует InterruptibleChannel и т. Д.). , EDIT: ... и если выбрано InterruptedException, это не подавляется.
  3. И да, позвоните только get(), если будущее isDone() (потому что оно находится в основном потоке, не управляемом вашим executorService).

Окончательный код будет делить причину downvote, так что я могу улучшить свои вопросы в будущем

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

У меня есть незначительный каламбур с формулировкой № 2: даже если код вызывает сон или ожидание и т. Д., Он все равно может отключить InterruptedException контрпродуктивным способом. все еще, +1. –

+0

Спасибо!Это было очень полезно. – mindreader

0

РОУ awaintTermination:

Блокирует до тех пор, пока все задачи не завершили выполнение после запроса на завершение работы, или не произойдет тайм-аут, или текущий поток не будет прерван, в зависимости от того, что произойдет раньше.

Это будет сделано через 5 секунд, но сгенерированный поток все еще работает, и это не поток демона, поэтому код будет продолжать работать до завершения дочернего потока.

И voidFuture.get() будет заблокирован до возвращения.

+0

Спасибо за ваш ответ! То, что я пытаюсь достичь, состоит в том, что вызываемый должен быть помечен как тайм-аут и должен вызывать исключение в таком случае. Можете ли вы дать мне несколько указаний на то, как это можно достичь? – mindreader

+0

Кроме того, я немного смущен, потому что ExecutorService.awaitTermination(), похоже, ничего не добивается. – mindreader

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

  • Нет связанных вопросов^_^