Exécutorcompletionservice? Pourquoi en avoir besoin si nous en avons tous?
  si nous utilisons un    ExecutorCompletionService    nous pouvons soumettre une série de tâches comme  Callable  s et obtenir le résultat en interaction avec le  CompletionService  comme un  queue  .    
  Mais il y a aussi le  invokeAll  de  ExecutorService  qui accepte un  Collection  de tâches et nous obtenons une liste de  Future  pour récupérer les résultats.    
  autant que je puisse dire, il n'y a aucun avantage à utiliser l'un ou l'autre (sauf que nous évitons une boucle for en utilisant un invokeAll que nous aurions à submit les tâches au CompletionService ) et essentiellement ils sont la même idée avec une légère différence.    
alors pourquoi y a-t-il deux façons différentes de soumettre une série de tâches? Ai-je raison de dire que les performances sont équivalentes? Est-il un cas que l'un est plus adapté que les autres? Je ne peux pas penser à un.
4 réponses
 en utilisant un ExecutorCompletionService.poll/take , vous recevez le Future  s comme ils terminent, dans l'ordre d'achèvement (plus ou moins). En utilisant  ExecutorService.invokeAll , vous n'avez pas ce pouvoir; soit vous bloquez jusqu'à ce que tout soit terminé, soit vous spécifiez un délai après lequel les incomplets sont annulés.  
static class SleepingCallable implements Callable<String> {
  final String name;
  final long period;
  SleepingCallable(final String name, final long period) {
    this.name = name;
    this.period = period;
  }
  public String call() {
    try {
      Thread.sleep(period);
    } catch (InterruptedException ex) { }
    return name;
  }
}
  maintenant, ci-dessous je vais vous montrer comment  invokeAll  fonctionne:  
final ExecutorService pool = Executors.newFixedThreadPool(2);
final List<? extends Callable<String>> callables = Arrays.asList(
    new SleepingCallable("quick", 500),
    new SleepingCallable("slow", 5000));
try {
  for (final Future<String> future : pool.invokeAll(callables)) {
    System.out.println(future.get());
  }
} catch (ExecutionException | InterruptedException ex) { }
pool.shutdown();
produit le résultat suivant:
C:\dev\scrap>java CompletionExample
... after 5 s ...
quick
slow
 en utilisant  CompletionService , nous voyons une sortie différente:  
final ExecutorService pool = Executors.newFixedThreadPool(2);
final CompletionService<String> service = new ExecutorCompletionService<String>(pool);
final List<? extends Callable<String>> callables = Arrays.asList(
    new SleepingCallable("slow", 5000),
    new SleepingCallable("quick", 500));
for (final Callable<String> callable : callables) {
  service.submit(callable);
}
pool.shutdown();
try {
  while (!pool.isTerminated()) {
    final Future<String> future = service.take();
    System.out.println(future.get());
  }
} catch (ExecutionException | InterruptedException ex) { }
produit le résultat suivant:
C:\dev\scrap>java CompletionExample
... after 500 ms ...
quick
... after 5 s ...
slow
notez que les heures sont relatives au démarrage du Programme, pas au message précédent.
vous pouvez trouver le code complet sur les deux ici .
 en utilisant un ExecutorCompletionService , vous pouvez être immédiatement informé lorsque chacun de vos travaux est terminé.  En comparaison,  ExecutorService.invokeAll(...)  attend pour    tout    de vos travaux à compléter avant de retourner la collecte de  Future  s:  
// this waits until _all_ of the jobs complete
List<Future<Object>> futures = threadPool.invokeAll(...);
  au lieu de cela, lorsque vous utilisez un  ExecutorCompletionService , vous serez en mesure d'obtenir les travaux dès que chacun d'eux complète ce qui vous permet (par exemple) de les envoyer pour le traitement dans un autre pool de thread, log les résultats, etc..  
ExecutorService threadPool = Executors.newFixedThreadPool(2);
ExecutorCompletionService<Result> compService
      = new ExecutorCompletionService<Result>(threadPool);
for (MyJob job : jobs) {
    compService.submit(job);
}
// shutdown the pool but the jobs submitted continue to run
threadPool.shutdown();
while (!threadPool.isTerminated()) {
    // the take() blocks until any of the jobs complete
    // this joins with the jobs in the order they _finish_
    Future<Result> future = compService.take();
    // this get() won't block
    Result result = future.get();
    // you can then put the result in some other thread pool or something
    // to immediately start processing it
    someOtherThreadPool.submit(new SomeNewJob(result));
}
Je n'ai jamais réellement utilisé Executorcompletservice, mais je pense que le cas où cela pourrait être plus utile que" normal " ExecutorService serait quand vous voulez recevoir les Futures des tâches terminées dans l'ordre d'achèvement. Avec invokeAll, vous obtenez juste une liste qui peut contenir un mélange de tâches incomplètes et achevées à tout moment.
la Comparaison en Considérant seulement l'Ordre des Résultats:
  lorsque nous utilisons  CompletionService  chaque fois qu'une tâche Soumise est terminée, le résultat sera poussé dans la file d'attente (ordre d'achèvement). Puis l'ordre des travaux soumis et les résultats retournés n'est plus le même. Donc, si vous êtes préoccupé par l'ordre quelles tâches ont été exécutées utiliser  CompletionService   
  où comme  invokeAll  renvoie une liste de Futures représentant les tâches, dans le même l'ordre établi par l'itérateur pour la liste des tâches, chacun de qui a terminé.