2013-05-10 4 views
3

я следующий код хэшированного:Как дождаться завершения всех вызовов, прежде чем продолжить?

public class MyCallable implements Callable<Long> { 
    @Override 
    public Long call() throws Exception { 
     // Do stuff... 
    } 
} 

public class MyController { 
    private ExecutorService executor = Executos.newCachedTreadPool(); 

    public Long concurrentDoStuff() { 
     List<MyCallable> workers = makeWorkers(); 

     List<Long> allResults = new ArrayList<Long>(); 
     for(MyCallable worker : workers) { 
      Future<Long> workerResults = executor.submit(worker); 

      try { 
       allResults.add(workerResults.get()); 
      } catch(InterruptedException ie) { 
       // Handle... 
      } catch(ExecutionException ee) { 
       // Handle... 
      } 
     } 

     // Question: how do I pause here and wait for all workers to finish? 
    } 
} 

После for -loop, я хочу, чтобы ждать, пока все рабочие, чтобы закончить, прежде чем продолжить дальше. Каков наилучший/безопасный/наиболее эффективный способ сделать это? Заранее спасибо!

+1

Вы хотите сначала представить все свои рабочие места, а затем ждать их результатов. В вашем коде вы ждете каждого результата, прежде чем окупить следующие задания, которые победят параллелизм. –

+0

+1 @RalfH - вы должны хранить список фьючерсов и не разыгрывать их, пока не представите все задания. – Alex

+0

Также вы должны скопировать/вставить код. У вас есть опечатки в приведенном выше! –

ответ

3

Вы должны закрыть Исполнителя с помощью shutDown, а затем дождаться, пока все задания будут обработаны с помощью awaitTermination.

+1

Спасибо @ Ralf H (+1) - где бы я разместил эти 2 вызова? – IAmYourFaja

+0

На самом деле вы можете использовать 'CompletionService'. –

2

Вы можете позвонить:

executor.shutdown(); 
executor.awaitTermination(Long.MAX_VALUE , TimeUnit.NANOSECONDS); 

Это будет ждать (почти) на неопределенное время для выполнения задач, чтобы закончить.

+0

Спасибо @ Duncan Jones (+1) - где бы я разместил эти 2 звонка? – IAmYourFaja

+1

это будет ждать долгое время, но не так долго, как вы могли бы подумать. Сначала сумма будет конвертирована в наносекунды и переполнена. –

+0

разместите эти вызовы после того, как вы представили все задания. –

4

Использовать CountDownLatch.

  • Инициализировать его с числом рабочих
  • Передайте ссылку на защелку в конструкторе рабочего
  • Когда работник будет сделано, позвоните countDown
  • Вызов await в главном потоке, и он будет блокировать пока рабочие не будут выполнены.

Это более универсальное решение, чем использование методов службы-исполнителя.

+0

Это хорошая альтернатива. –

+0

Спасибо @Alex (+1) - как этот подход справедлив иначе, чем стратегия 'shutdown' /' awaitTermination', рекомендованная другими? Это более эффективно? Безопаснее?Еще раз спасибо! – IAmYourFaja

+0

не является ни более эффективным, ни безопасным, он просто вводит другой объект параллелизма. Как бы то ни было, Исполнитель может управлять статусом завершения с помощью shutdown и ждать завершения. Если вы все равно получаете() все свои фьючерсы, вы также убедитесь, что они завершены. Поэтому, если вы получите() свое последнее Будущее, вы знаете, что Executor прекращен. –

0

Существует удобный способ.

ExecutorService.invokeAll(List<Callable> callables); 

Она возвращает List<Future> объектов, так что вы можете получить возврат объектов всех ваших индивидуальных call() методов.

Вы можете получить экземпляр ExecutorService по телефону Executors.new....()

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