Comment attendre la fin de tous les threads, en utilisant ExecutorService?


381

J'ai besoin d'exécuter un certain nombre de tâches 4 à la fois, quelque chose comme ceci:

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
    taskExecutor.execute(new MyTask());
}
//...wait for completion somehow

Comment puis-je être averti une fois que tous sont terminés? Pour l'instant, je ne peux penser à rien de mieux que de définir un compteur de tâches global et de le diminuer à la fin de chaque tâche, puis de surveiller en boucle infinie ce compteur pour devenir 0; ou obtenez une liste de Futures et le moniteur de boucle infinie est fait pour chacun d'eux. Quelles sont les meilleures solutions n'impliquant pas de boucles infinies?

Merci.

Réponses:


446

Fondamentalement, ExecutorServicevous appelez shutdown()puis awaitTermination():

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}
taskExecutor.shutdown();
try {
  taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
  ...
}

9
c'est exactement à cela que sont destinés les arrêts / attendus
matt b

31
C'est un bon modèle si cette gestion des tâches est un événement ponctuel. Si cela est fait à plusieurs reprises pendant le même runtime, cependant, ce n'est pas optimal, car vous créeriez et détruiriez des threads à chaque fois qu'il est exécuté.
sjlee

44
Je recherche une documentation officielle Long.MAX_VALUE, TimeUnit.NANOSECONDSéquivalente à l'absence de délai d'expiration.
Sam Harwell

15
Je ne peux pas croire que vous devez utiliser shutdown pour rejoindre tous les threads actuels (après avoir utilisé shutdown, vous ne pouvez plus jamais utiliser l'exécuteur). Suggérez d'utiliser la liste de Future à la place ...
rogerdpack

20
@SamHarwell voir la documentation du java.util.concurrentpaquet dans la section: Pour attendre "indéfiniment", vous pouvez utiliser une valeur deTimingLong.MAX_VALUE
beluchin

174

Utilisez un CountDownLatch :

CountDownLatch latch = new CountDownLatch(totalNumberOfTasks);
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}

try {
  latch.await();
} catch (InterruptedException E) {
   // handle
}

et au sein de votre tâche (joindre dans try / enfin)

latch.countDown();

3
Il n'y a pas 4 tâches. Il y a "un certain nombre de tâches" effectuées 4 à la fois.
cletus

2
Désolé, j'ai mal compris la question. Oui, le nombre de tâches devrait être l'argument du constructeur CountDownLatch
ChssPly76

3
Je trouve cette solution plus élégante que les autres, on dirait qu'elle a été faite à cet effet, et c'est simple et direct.
wvdschel

3
Et si vous ne connaissez pas le nombre de tâches avant de commencer?
cletus

11
@cletus - alors vous n'utilisez pas un CountDownLatch :-) Attention, je ne dis pas que cette approche est meilleure que la vôtre. Cependant, je trouve que dans de vrais scénarios de vie , je ne sais le nombre de tâches, les paramètres de pool de threads ne doivent être configurable par le déploiement et les piscines peuvent être réutilisés. Donc, j'ai généralement des pools de threads injectés par Spring et les définir comme des prototypes et les arrêter manuellement uniquement pour attendre la fin des threads semble moins qu'idéal.
ChssPly76

82

ExecutorService.invokeAll() le fait pour vous.

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
List<Callable<?>> tasks; // your tasks
// invokeAll() returns when all tasks are complete
List<Future<?>> futures = taskExecutor.invokeAll(tasks);

La difficulté vient si / quand vous avez le début les "4" fils un à la fois, par morceaux, puis rejoignez / laissez terminer les 4 ...
rogerdpack

@rogerdpack: J'apprends encore ces exécuteurs et tout ça. Mais en réponse à ce que vous demandez. Les 4 threads à la fois ne doivent-ils pas faire partie d'une tâche batch exécutée à l'aide de la réponse ci-dessus?
Mukul Goel

3
Cette méthode ne fonctionnera que si vous connaissez le nombre de tâches à l'avance.
Konstantin

3
Je pense qu'à futuresleur retour, les tâches ne sont pas terminées. Ils pourraient se terminer à l'avenir et vous aurez un lien vers le résultat. C'est pourquoi cela s'appelle un Future. Vous disposez de la méthode Future.get () , qui attend la fin de la tâche pour obtenir un résultat.
AlikElzin-kilaka

5
@ AlikElzin-kilaka Citation des JavaDocs (liée dans la réponse): "Exécute les tâches données, renvoyant une liste de Futures contenant leur statut et leurs résultats une fois tous terminés. Future.isDone () est vrai pour chaque élément de la liste renvoyée. "
Hulk

47

Vous pouvez également utiliser Lists of Futures:

List<Future> futures = new ArrayList<Future>();
// now add to it:
futures.add(executorInstance.submit(new Callable<Void>() {
  public Void call() throws IOException {
     // do something
    return null;
  }
}));

puis lorsque vous souhaitez vous joindre à chacun d'eux, c'est essentiellement l'équivalent de se joindre à chacun d'eux (avec l'avantage supplémentaire qu'il relance les exceptions des threads enfants au principal):

for(Future f: this.futures) { f.get(); }

Fondamentalement, l'astuce consiste à appeler .get () sur chaque Future un à la fois, au lieu d'appeler en boucle infinie isDone () on (tous ou chacun). Vous êtes donc assuré de "passer" à travers et après ce bloc dès que le dernier thread se termine. La mise en garde est que, puisque l'appel .get () relance des exceptions, si l'un des threads meurt, vous le relancerez peut-être avant la fin des autres threads [pour éviter cela, vous pouvez ajouter un catch ExecutionExceptionautour de l'appel get ]. L'autre mise en garde est qu'il conserve une référence à tous les threads, donc s'ils ont des variables locales de thread, ils ne seront collectés qu'après avoir passé ce bloc (bien que vous puissiez contourner ce problème, si cela devenait un problème, en supprimant L'avenir est hors de la liste des tableaux). Si vous vouliez savoir quel avenir "finit le premier"https://stackoverflow.com/a/31885029/32453


3
Pour savoir qui "termine en premier", utilisez ExecutorCompletionService.take: stackoverflow.com/a/11872604/199364
ToolmakerSteve

34

En Java8, vous pouvez le faire avec CompletableFuture :

ExecutorService es = Executors.newFixedThreadPool(4);
List<Runnable> tasks = getTasks();
CompletableFuture<?>[] futures = tasks.stream()
                               .map(task -> CompletableFuture.runAsync(task, es))
                               .toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();    
es.shutdown();

3
Il s'agit d'une solution très élégante.
mattvonb

ExecutorService es = Executors.newFixedThreadPool(4); List< Future<?>> futures = new ArrayList<>(); for(Runnable task : taskList) { futures.add(es.submit(task)); } for(Future<?> future : futures) { try { future.get(); }catch(Exception e){ // do logging and nothing else } }
user2862544

@AdamSkywalker est waitTermination () nécessaire après es.shutdown ()?
gaurav

@gaurav lorsque vous appelez shutdown, certaines tâches peuvent ne pas encore être terminées. Donc, waitTermination bloquera le thread appelant jusqu'à ce que tout soit fait. Cela dépend si vous devez attendre les résultats dans ce fil ou non.
AdamSkywalker

@AdamSkywalker excellente réponse. est logique de ne pas appeler waitTermination () si je n'ai pas besoin d'attendre les résultats.
gaurav

26

Juste mes deux cents. Pour surmonter l'exigence de CountDownLatchconnaître le nombre de tâches à l'avance, vous pouvez le faire à l'ancienne en utilisant un simple Semaphore.

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
int numberOfTasks=0;
Semaphore s=new Semaphore(0);
while(...) {
    taskExecutor.execute(new MyTask());
    numberOfTasks++;
}

try {
    s.aquire(numberOfTasks);
...

Dans votre tâche, appelez s.release()comme vous le feriezlatch.countDown();


En voyant cela, je me suis d'abord demandé si ce serait un problème si certains releaseappels se produisent avant l' acquireappel, mais après avoir lu la documentation de Semaphore, je vois que ça va.
ToolmakerSteve

13

Un peu tard pour le jeu mais pour finir ...

Au lieu d '«attendre» que toutes les tâches soient terminées, vous pouvez penser en termes du principe hollywoodien «ne m'appelez pas, je vous appellerai» - quand j'ai fini. Je pense que le code résultant est plus élégant ...

La goyave propose des outils intéressants pour y parvenir.

Un exemple ::

Enveloppez un ExecutorService dans un ListeningExecutorService ::

ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));

Soumettre une collection de callables pour exécution ::

for (Callable<Integer> callable : callables) {
  ListenableFuture<Integer> lf = service.submit(callable);
  // listenableFutures is a collection
  listenableFutures.add(lf)
});

Maintenant l'essentiel:

ListenableFuture<List<Integer>> lf = Futures.successfulAsList(listenableFutures);

Attachez un rappel à ListenableFuture, que vous pouvez utiliser pour être averti lorsque tous les futurs se terminent:

        Futures.addCallback(lf, new FutureCallback<List<Integer>>() {
        @Override
        public void onSuccess(List<Integer> result) {
            log.info("@@ finished processing {} elements", Iterables.size(result));
            // do something with all the results
        }

        @Override
        public void onFailure(Throwable t) {
            log.info("@@ failed because of :: {}", t);
        }
    });

Cela offre également l'avantage que vous pouvez collecter tous les résultats en un seul endroit une fois le traitement terminé ...

Plus d'informations ici


2
Très propre. Fonctionne parfaitement, même sur Android. Juste dû utiliser runOnUiThread()dans onSuccess().
DSchmidt

12

La classe CyclicBarrier dans Java 5 et versions ultérieures est conçue pour ce genre de chose.


7
Cool, je ne me souviens jamais du nom de cette structure de données. Cependant, ne convient que si vous connaissez à l'avance le nombre de tâches qui seront mises en file d'attente.
ᆼ ᆺ ᆼ

oui, vous penseriez que vous seriez en mesure de franchir la barrière avec le thread actuel et tous les threads enfants, puis quand vous l'auriez passé, vous sauriez que les threads enfants ont été effectués ...
rogerdpack

En fait, c'est une mauvaise réponse. CyclicBarrier conçu pour les portions. CountDownLatch conçu pour l'événement en attente
gstackoverflow

7

Suivez l'une des approches ci-dessous.

  1. Parcourez toutes les tâches futures , revenez de submitdessus ExecutorServiceet vérifiez l'état en bloquant l'appel get()sur l' Futureobjet comme suggéré parKiran
  2. Utilisation invokeAll()sur ExecutorService
  3. CountDownLatch
  4. ForkJoinPool ou Executors.html # newWorkStealingPool
  5. Utilisez les shutdown, awaitTermination, shutdownNowAPI de ThreadPoolExecutor dans l'ordre approprié

Questions SE connexes:

Comment CountDownLatch est-il utilisé dans le multithreading Java?

Comment arrêter correctement Java ExecutorService


6

voici deux options, confondez un peu laquelle est la meilleure.

Option 1:

ExecutorService es = Executors.newFixedThreadPool(4);
List<Runnable> tasks = getTasks();
CompletableFuture<?>[] futures = tasks.stream()
                               .map(task -> CompletableFuture.runAsync(task, es))
                               .toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();    
es.shutdown();

Option 2:

ExecutorService es = Executors.newFixedThreadPool(4);
List< Future<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
    futures.add(es.submit(task));
}

for(Future<?> future : futures) {
    try {
        future.get();
    }catch(Exception e){
        // do logging and nothing else
    }
}
es.shutdown();

Ici, mettre future.get (); dans try catch est une bonne idée non?


5

Vous pouvez envelopper vos tâches dans un autre exécutable, qui enverra des notifications:

taskExecutor.execute(new Runnable() {
  public void run() {
    taskStartedNotification();
    new MyTask().run();
    taskFinishedNotification();
  }
});

1
Cela m'a pris un certain temps pour voir comment cela résoudrait la question d'OP. Tout d'abord, notez que cet habillage est de chaque tâche, pas du code qui démarre toutes les tâches. Vraisemblablement, chaque début incrémenterait un compteur, et chaque arrivée décrémenterait ce compteur, ou incrémenterait un completedcompteur. Ainsi, après les avoir tous démarrés, à chaque notification, vous pourriez déterminer si toutes les tâches sont terminées. Notez qu'il est vital d'utiliser try/finallypour qu'une notification terminée (ou une notification alternative en catchbloc) soit donnée même si une tâche échoue. Sinon, j'attendrais pour toujours.
ToolmakerSteve

3

Je viens d'écrire un exemple de programme qui résout votre problème. Aucune implémentation concise n'a été donnée, je vais donc en ajouter une. Bien que vous puissiez utiliser executor.shutdown()et executor.awaitTermination(), ce n'est pas la meilleure pratique car le temps pris par différents threads serait imprévisible.

ExecutorService es = Executors.newCachedThreadPool();
    List<Callable<Integer>> tasks = new ArrayList<>();

    for (int j = 1; j <= 10; j++) {
        tasks.add(new Callable<Integer>() {

            @Override
            public Integer call() throws Exception {
                int sum = 0;
                System.out.println("Starting Thread "
                        + Thread.currentThread().getId());

                for (int i = 0; i < 1000000; i++) {
                    sum += i;
                }

                System.out.println("Stopping Thread "
                        + Thread.currentThread().getId());
                return sum;
            }

        });
    }

    try {
        List<Future<Integer>> futures = es.invokeAll(tasks);
        int flag = 0;

        for (Future<Integer> f : futures) {
            Integer res = f.get();
            System.out.println("Sum: " + res);
            if (!f.isDone()) 
                flag = 1;
        }

        if (flag == 0)
            System.out.println("SUCCESS");
        else
            System.out.println("FAILED");

    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }

Il est bon que vous montriez l'utilisation de future.get - une bonne alternative à connaître. Mais pourquoi considérez-vous qu'il vaut mieux attendre indéfiniment que de fixer un délai d'expiration maximum acceptable? Plus important encore, il n'y a aucune raison de faire toute cette logique, quand on peut simplement donner un temps vraiment très long pour attendre la terminaison, si vous voulez attendre (essentiellement pour toujours) jusqu'à ce que toutes les tâches soient terminées.
ToolmakerSteve

Ce n'est pas différent des solutions déjà présentées ici. Votre juste solution est la même que celle présentée par @sjlee
pulp_fiction

Je ne sais pas pourquoi vous devez vérifier que c'est fait selon oracle doc, invokeAll ne reviendra que "lorsque tout sera terminé ou que le délai expirera, selon la première éventualité"
Mashrur

3

Juste pour fournir plus d'alternatives ici différentes pour utiliser les verrous / barrières. Vous pouvez également obtenir les résultats partiels jusqu'à ce qu'ils finissent tous d'utiliser CompletionService .

De Java Concurrency en pratique: "Si vous avez un lot de calculs à soumettre à un exécuteur et que vous souhaitez récupérer leurs résultats dès qu'ils sont disponibles, vous pouvez conserver le futur associé à chaque tâche et interroger à plusieurs reprises pour l'achèvement en appelant get avec un délai d'attente nul. C'est possible, mais fastidieux . Heureusement, il existe une meilleure solution : un service de finition. "

Ici l'implémentation

public class TaskSubmiter {
    private final ExecutorService executor;
    TaskSubmiter(ExecutorService executor) { this.executor = executor; }
    void doSomethingLarge(AnySourceClass source) {
        final List<InterestedResult> info = doPartialAsyncProcess(source);
        CompletionService<PartialResult> completionService = new ExecutorCompletionService<PartialResult>(executor);
        for (final InterestedResult interestedResultItem : info)
            completionService.submit(new Callable<PartialResult>() {
                public PartialResult call() {
                    return InterestedResult.doAnOperationToGetPartialResult();
                }
        });

    try {
        for (int t = 0, n = info.size(); t < n; t++) {
            Future<PartialResult> f = completionService.take();
            PartialResult PartialResult = f.get();
            processThisSegment(PartialResult);
            }
        } 
        catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } 
        catch (ExecutionException e) {
            throw somethinghrowable(e.getCause());
        }
    }
}

3

Ceci est ma solution, basée sur l'astuce "AdamSkywalker", et ça marche

package frss.main;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestHilos {

    void procesar() {
        ExecutorService es = Executors.newFixedThreadPool(4);
        List<Runnable> tasks = getTasks();
        CompletableFuture<?>[] futures = tasks.stream().map(task -> CompletableFuture.runAsync(task, es)).toArray(CompletableFuture[]::new);
        CompletableFuture.allOf(futures).join();
        es.shutdown();

        System.out.println("FIN DEL PROCESO DE HILOS");
    }

    private List<Runnable> getTasks() {
        List<Runnable> tasks = new ArrayList<Runnable>();

        Hilo01 task1 = new Hilo01();
        tasks.add(task1);

        Hilo02 task2 = new Hilo02();
        tasks.add(task2);
        return tasks;
    }

    private class Hilo01 extends Thread {

        @Override
        public void run() {
            System.out.println("HILO 1");
        }

    }

    private class Hilo02 extends Thread {

        @Override
        public void run() {
            try {
                sleep(2000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("HILO 2");
        }

    }


    public static void main(String[] args) {
        TestHilos test = new TestHilos();
        test.procesar();
    }
}

2

Vous pouvez utiliser ce code:

public class MyTask implements Runnable {

    private CountDownLatch countDownLatch;

    public MyTask(CountDownLatch countDownLatch {
         this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
         try {
             //Do somethings
             //
             this.countDownLatch.countDown();//important
         } catch (InterruptedException ex) {
              Thread.currentThread().interrupt();
         }
     }
}

CountDownLatch countDownLatch = new CountDownLatch(NUMBER_OF_TASKS);
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
for (int i = 0; i < NUMBER_OF_TASKS; i++){
     taskExecutor.execute(new MyTask(countDownLatch));
}
countDownLatch.await();
System.out.println("Finish tasks");

2

J'ai créé l'exemple de travail suivant. L'idée est d'avoir un moyen de traiter un pool de tâches (j'utilise une file d'attente comme exemple) avec de nombreux threads (déterminés par programme par numberOfTasks / threshold), et d'attendre que tous les threads soient terminés pour continuer avec un autre traitement.

import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/** Testing CountDownLatch and ExecutorService to manage scenario where
 * multiple Threads work together to complete tasks from a single
 * resource provider, so the processing can be faster. */
public class ThreadCountDown {

private CountDownLatch threadsCountdown = null;
private static Queue<Integer> tasks = new PriorityQueue<>();

public static void main(String[] args) {
    // Create a queue with "Tasks"
    int numberOfTasks = 2000;
    while(numberOfTasks-- > 0) {
        tasks.add(numberOfTasks);
    }

    // Initiate Processing of Tasks
    ThreadCountDown main = new ThreadCountDown();
    main.process(tasks);
}

/* Receiving the Tasks to process, and creating multiple Threads
* to process in parallel. */
private void process(Queue<Integer> tasks) {
    int numberOfThreads = getNumberOfThreadsRequired(tasks.size());
    threadsCountdown = new CountDownLatch(numberOfThreads);
    ExecutorService threadExecutor = Executors.newFixedThreadPool(numberOfThreads);

    //Initialize each Thread
    while(numberOfThreads-- > 0) {
        System.out.println("Initializing Thread: "+numberOfThreads);
        threadExecutor.execute(new MyThread("Thread "+numberOfThreads));
    }

    try {
        //Shutdown the Executor, so it cannot receive more Threads.
        threadExecutor.shutdown();
        threadsCountdown.await();
        System.out.println("ALL THREADS COMPLETED!");
        //continue With Some Other Process Here
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
}

/* Determine the number of Threads to create */
private int getNumberOfThreadsRequired(int size) {
    int threshold = 100;
    int threads = size / threshold;
    if( size > (threads*threshold) ){
        threads++;
    }
    return threads;
}

/* Task Provider. All Threads will get their task from here */
private synchronized static Integer getTask(){
    return tasks.poll();
}

/* The Threads will get Tasks and process them, while still available.
* When no more tasks available, the thread will complete and reduce the threadsCountdown */
private class MyThread implements Runnable {

    private String threadName;

    protected MyThread(String threadName) {
        super();
        this.threadName = threadName;
    }

    @Override
    public void run() {
        Integer task;
        try{
            //Check in the Task pool if anything pending to process
            while( (task = getTask()) != null ){
                processTask(task);
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }finally {
            /*Reduce count when no more tasks to process. Eventually all
            Threads will end-up here, reducing the count to 0, allowing
            the flow to continue after threadsCountdown.await(); */
            threadsCountdown.countDown();
        }
    }

    private void processTask(Integer task){
        try{
            System.out.println(this.threadName+" is Working on Task: "+ task);
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}
}

J'espère que cela aide!


1

Vous pouvez utiliser votre propre sous-classe d' ExecutorCompletionService pour envelopper taskExecutor, et votre propre implémentation de BlockingQueue pour être informé lorsque chaque tâche se termine et effectuer tout rappel ou toute autre action que vous souhaitez lorsque le nombre de tâches terminées atteint votre objectif souhaité.


1

vous devez utiliser executorService.shutdown()et executorService.awaitTerminationméthode.

Un exemple comme suit:

public class ScheduledThreadPoolExample {

    public static void main(String[] args) throws InterruptedException {
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
        executorService.scheduleAtFixedRate(() -> System.out.println("process task."),
                0, 1, TimeUnit.SECONDS);

        TimeUnit.SECONDS.sleep(10);
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.DAYS);
    }

}

est en attenteTermination () nécessaire après l'arrêt () /
gaurav

1

Donc, je poste ma réponse à partir d'une question liée ici, au cas où quelqu'un voudrait un moyen plus simple de le faire

ExecutorService executor = Executors.newFixedThreadPool(10);
CompletableFuture[] futures = new CompletableFuture[10];
int i = 0;
while (...) {
    futures[i++] =  CompletableFuture.runAsync(runner, executor);
}

CompletableFuture.allOf(futures).join(); // THis will wait until all future ready.

0

Java 8 - Nous pouvons utiliser l'API de flux pour traiter le flux. Veuillez consulter l'extrait ci-dessous

final List<Runnable> tasks = ...; //or any other functional interface
tasks.stream().parallel().forEach(Runnable::run) // Uses default pool

//alternatively to specify parallelism 
new ForkJoinPool(15).submit(
          () -> tasks.stream().parallel().forEach(Runnable::run) 
    ).get();

2
Salut Vlad, bienvenue sur StackOverflow. Pouvez-vous modifier votre réponse pour expliquer comment cela répond à la question et ce que fait le code? Les réponses codées uniquement sont déconseillées ici. Je vous remercie!
Tim Malone

Ce post parle de simultanéité. Parallélisme! = Concurrence
GabrielBB

0

ExecutorService WORKER_THREAD_POOL 
  = Executors.newFixedThreadPool(10);
CountDownLatch latch = new CountDownLatch(2);
for (int i = 0; i < 2; i++) {
    WORKER_THREAD_POOL.submit(() -> {
        try {
            // doSomething();
            latch.countDown();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    });
}

// wait for the latch to be decremented by the two remaining threads
latch.await();

Si vous doSomething()lancez d'autres exceptions, le latch.countDown()semble ne s'exécutera pas, alors que dois-je faire?


0

si vous utilisez plus de thread ExecutionServices SEQUENTIELLEMENT et que vous souhaitez attendre la fin de CHAQUE EXECUTIONSERVICE. La meilleure façon est comme ci-dessous;

ExecutorService executer1 = Executors.newFixedThreadPool(THREAD_SIZE1);
for (<loop>) {
   executer1.execute(new Runnable() {
            @Override
            public void run() {
                ...
            }
        });
} 
executer1.shutdown();

try{
   executer1.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);

   ExecutorService executer2 = Executors.newFixedThreadPool(THREAD_SIZE2);
   for (true) {
      executer2.execute(new Runnable() {
            @Override
            public void run() {
                 ...
            }
        });
   } 
   executer2.shutdown();
} catch (Exception e){
 ...
}

-1

Cela pourrait aider

Log.i(LOG_TAG, "shutting down executor...");
executor.shutdown();
while (true) {
                try {
                    Log.i(LOG_TAG, "Waiting for executor to terminate...");
                    if (executor.isTerminated())
                        break;
                    if (executor.awaitTermination(5000, TimeUnit.MILLISECONDS)) {
                        break;
                    }
                } catch (InterruptedException ignored) {}
            }

-1

Vous pouvez appeler waitTillDone () sur cette classe Runner :

Runner runner = Runner.runner(4); // create pool with 4 threads in thread pool

while(...) {
    runner.run(new MyTask()); // here you submit your task
}


runner.waitTillDone(); // and this blocks until all tasks are finished (or failed)


runner.shutdown(); // once you done you can shutdown the runner

Vous pouvez réutiliser cette classe et appeler waitTillDone () autant de fois que vous le souhaitez avant d'appeler shutdown (), et votre code est extrêmement simple . De plus, vous n'avez pas à connaître le nombre de tâches à l' avance.

Pour l'utiliser, ajoutez simplement cette compile 'com.github.matejtymes:javafixes:1.3.1'dépendance gradle / maven à votre projet.

Plus de détails ici:

https://github.com/MatejTymes/JavaFixes


-2

Il existe une méthode dans l'exécuteur getActiveCount()- qui donne le nombre de threads actifs.

Après avoir enjambé le fil, nous pouvons vérifier si la activeCount()valeur est 0. Une fois que la valeur est nulle, cela signifie qu'aucun thread actif n'est en cours d'exécution, ce qui signifie que la tâche est terminée:

while (true) {
    if (executor.getActiveCount() == 0) {
    //ur own piece of code
    break;
    }
}

3
Pas une bonne idée, voir stackoverflow.com/a/7271685/1166992 et le javadoc: "Renvoie le nombre approximatif de threads qui exécutent activement des tâches."
Olivier Faucheux du
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.