Como aguardar a conclusão de todos os threads, usando ExecutorService?

381

Preciso executar uma quantidade de tarefas 4 de cada vez, algo como isto:

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

Como posso ser notificado quando todos eles estiverem completos? Por enquanto, não consigo pensar em nada melhor do que definir um contador de tarefas global e diminuí-lo no final de cada tarefa; em seguida, monitore em loop infinito esse contador para se tornar 0; ou obtenha uma lista de futuros e no monitor de loop infinito é feito para todos eles. Quais são as melhores soluções que não envolvem loops infinitos?

Obrigado.

serg
fonte

Respostas:

446

Basicamente em uma ExecutorServicechamada shutdown()e depois awaitTermination():

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}
taskExecutor.shutdown();
try {
  taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
  ...
}
cleto
fonte
9
Este é exatamente o shutdown / awaitTermination são destinadas para
matt b
31
É um bom padrão se esse tratamento de tarefas for um evento único. Se isso for feito repetidamente durante o mesmo tempo de execução, no entanto, não será o ideal, pois você criaria e derrubaria threads repetidamente toda vez que for executado.
Sjlee 9/08/09
44
Estou procurando por qualquer documentação oficial Long.MAX_VALUE, TimeUnit.NANOSECONDSequivalente a não ter um tempo limite.
22412 Sam Harwell
15
Não acredito que você precise usar o shutdown para ingressar em todos os threads atuais (depois de usar o shutdown, você não poderá usar o executor novamente). Sugerir usando a lista de Future em vez disso ...
rogerdpack
20
@SamHarwell ver o java.util.concurrentpacote de documentação sob a Timingseção: Para esperar "para sempre", você pode usar um valor deLong.MAX_VALUE
beluchin
174

Use um CountDownLatch :

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

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

e dentro da sua tarefa (coloque em try / finalmente)

latch.countDown();
ChssPly76
fonte
3
Não há 4 tarefas. Existem "algumas tarefas" executadas 4 de cada vez.
Cletus
2
Desculpe, eu não entendi a pergunta. Sim, número de tarefas deve ser o argumento para o construtor CountDownLatch
ChssPly76
3
Acho essa solução mais elegante que as outras, parece que foi feita para essa finalidade e é simples e direta.
Wvdschel 09/08/09
3
E se você não souber o número de tarefas antes de começar?
Cletus
11
@ Cletus - então você não usa um CountDownLatch :-) Lembre-se, não estou argumentando que essa abordagem seja melhor que a sua. No entanto, descobri que, em cenários da vida real , sei o número de tarefas, as configurações do conjunto de encadeamentos precisam ser configuráveis ​​por implantação e os conjuntos podem ser reutilizados. Por isso, normalmente eu tenho pools de threads injetados pelo Spring, defini-los como protótipos e desligá-los manualmente apenas para aguardar o término dos threads parece menos do que o ideal.
ChssPly76
82

ExecutorService.invokeAll() faz isso por você.

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
List<Callable<?>> tasks; // your tasks
// invokeAll() returns when all tasks are complete
List<Future<?>> futures = taskExecutor.invokeAll(tasks);
sjlee
fonte
A dificuldade vem se / quando você a começar os "4" threads um de cada vez, peça-wise, em seguida, juntar / vamos terminar todos os 4 ...
rogerdpack
@rogerdpack: Eu ainda estou aprendendo esses executores e outras coisas. Mas em resposta ao que você pergunta. Os 4 threads de cada vez não devem fazer parte de uma tarefa em lote que é executada usando a resposta acima?
Mukul Goel
3
Este método só funcionará se você souber o número de tarefas anteriormente.
Konstantin
3
Eu acho que quando os futuresretornados, as tarefas não foram concluídas. Eles podem ser concluídos no futuro e você terá um link para o resultado. É por isso que é chamado de Future. Você tem o método Future.get () , que aguardará a conclusão da tarefa para obter um resultado.
AlikElzin-Kilaka
5
@ AlikElzin-kilaka Citação dos JavaDocs (vinculados na resposta): "Executa as tarefas fornecidas, retornando uma lista de futuros mantendo seu status e resultados quando todos estiverem concluídos. Future.isDone () é verdadeiro para cada elemento da lista retornada. "
Hulk
47

Você também pode usar Listas de futuros:

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;
  }
}));

então, quando você deseja ingressar em todos eles, é essencialmente o equivalente a ingressar em cada um (com o benefício adicional de que ele gera exceções de threads filho para a principal):

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

Basicamente, o truque é chamar .get () em cada futuro, um de cada vez, em vez de um loop infinito de chamada isDone () ativada (todas ou cada). Portanto, você está garantido para "seguir em frente" através e além deste bloco assim que o último thread terminar. A ressalva é que, como a chamada .get () gera novamente exceções, se um dos threads morrer, você poderá aumentar isso possivelmente antes que os outros threads tenham sido concluídos [para evitar isso, adicione um https: // stackoverflow.com/a/31885029/32453catch ExecutionException chamada get ] A outra ressalva é que ele mantém uma referência a todos os encadeamentos, portanto, se eles tiverem variáveis ​​locais de encadeamento, não serão coletados até depois que você passar por esse bloco (embora você possa contornar isso, se houver algum problema, removendo O futuro está fora do ArrayList). Se você quiser saber qual futuro "termina primeiro"

rogerdpack
fonte
3
Para saber qual "termina primeiro", use ExecutorCompletionService.take: stackoverflow.com/a/11872604/199364
ToolmakerSteve
34

No Java8, você pode fazer isso com o 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();
AdamSkywalker
fonte
3
Esta é uma solução muito elegante.
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 é aguarditTermination () necessário após es.shutdown ()?
gaurav
@gaurav quando você encerra o desligamento, algumas tarefas ainda não estão concluídas. Portanto, waititmin irá bloquear o thread de chamada até que tudo esteja pronto. Depende se você precisa aguardar resultados nesse segmento ou não.
111319 AdamSkywalker
@AdamSkywalker ótima resposta. faz sentido não chamar waititTermination () se eu não precisar esperar pelos resultados.
gaurav
26

Apenas meus dois centavos. Para superar o requisito de CountDownLatchconhecer antecipadamente o número de tarefas, você pode fazer da maneira antiga usando um simples Semaphore.

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

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

Na sua tarefa, basta ligar s.release()como farialatch.countDown();

Stryba
fonte
Ao ver isso, primeiro me perguntei se seria um problema se algumas releasechamadas acontecessem antes da acquirechamada, mas depois de ler a documentação do Semáforo, vejo que está tudo bem.
Página
13

Um pouco tarde para o jogo, mas por uma questão de conclusão ...

Em vez de "esperar" que todas as tarefas terminem, você pode pensar em termos do princípio de Hollywood: "não me ligue, eu te ligo" - quando terminar. Eu acho que o código resultante é mais elegante ...

Goiaba oferece algumas ferramentas interessantes para fazer isso.

Um exemplo ::

Agrupar um ExecutorService em um ListeningExecutorService ::

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

Envie uma coleção de callables para execução:

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

Agora a parte essencial:

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

Anexe um retorno de chamada ao ListenableFuture, que você poderá usar para ser notificado quando todos os futuros forem concluídos:

        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);
        }
    });

Isso também oferece a vantagem de que você pode coletar todos os resultados em um único local após o término do processamento ...

Mais informações aqui

Răzvan Petruescu
fonte
2
Muito limpo. Funciona perfeitamente, mesmo no Android. Só tinha de usar runOnUiThread()no onSuccess().
DSchmidt
12

A classe CyclicBarrier no Java 5 e posterior foi projetada para esse tipo de coisa.

Pekka Enberg
fonte
7
Legal, nunca se lembra do nome dessa estrutura de dados. No entanto, apenas adequado se você souber de antemão a quantidade de tarefas que serão colocadas na fila.
ᆼ ᆺ ᆼ
sim você pensaria que você seria capaz de bater a barreira ao segmento atual, e todas as crianças threads, então, quando você passou você saberia os tópicos criança foram feito ...
rogerdpack
Na verdade, é uma resposta errada. CyclicBarrier projetado para porções. CountDownLatch projetado para esperando evento
gstackoverflow
7

Siga uma das abordagens abaixo.

  1. Percorrer todos futuras tarefas, voltou submitem ExecutorServicee verificar o estado com bloqueio de chamadas get()emFuture objeto como sugerido porKiran
  2. Use invokeAll()no ExecutorService
  3. CountDownLatch
  4. ForkJoinPool ou Executors.html # newWorkStealingPool
  5. Use shutdown, awaitTermination, shutdownNowAPIs do ThreadPoolExecutor na sequência apropriada

Perguntas relacionadas ao SE:

Como o CountDownLatch é usado no Multithreading Java?

Como desligar corretamente java ExecutorService

Ravindra babu
fonte
6

Aqui estão duas opções, apenas confundam qual é a melhor opção.

Opção 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();

Opção 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();

Aqui colocando future.get (); em tentar pegar é boa ideia né?

user2862544
fonte
5

Você pode agrupar suas tarefas em outro executável, que enviará notificações:

taskExecutor.execute(new Runnable() {
  public void run() {
    taskStartedNotification();
    new MyTask().run();
    taskFinishedNotification();
  }
});
Zed
fonte
11
Demorei um pouco para ver como isso resolveria a questão da OP. Primeiro, observe que esse agrupamento é de cada tarefa, não do código que inicia todas as tarefas. Presumivelmente, cada partida incrementaria um contador e cada finalização diminuiria esse contador ou incrementaria um completedcontador. Portanto, depois de iniciar todos eles, a cada notificação, poderá determinar se todas as tarefas foram concluídas. Observe que é vital usá- try/finallylo para que uma notificação finalizada (ou uma notificação alternativa em catchbloco) seja dada mesmo se uma tarefa falhar. Caso contrário, esperaria para sempre.
Página Inicial>
3

Acabei de escrever um programa de amostra que resolve seu problema. Não houve uma implementação concisa, portanto, adicionarei uma. Embora você possa usar executor.shutdown()e executor.awaitTermination(), não é a melhor prática, pois o tempo gasto por diferentes segmentos seria imprevisível.

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();
    }
Kiran
fonte
É bom que você mostre o uso de future.get - boa alternativa para conhecer. Mas por que você considera melhor esperar para sempre do que definir um tempo limite aceitável máximo? Mais importante ainda, não há razão para fazer toda essa lógica, quando se pode simplesmente dar um tempo muito, muito aguardado para aguardar o término, se você quiser esperar (essencialmente para sempre) até que todas as tarefas sejam concluídas.
Página
Isso não é diferente das soluções já apresentadas aqui. Sua solução justa é a mesma apresentada pelo @sjlee
pulp_fiction
Não sei por que você precisa verificar se, de acordo com o documento da Oracle, invokeAll retornará apenas "quando tudo estiver completo ou o tempo limite expirar, o que acontecer primeiro"
Mashrur 30/11/17
3

Só para fornecer mais alternativas aqui diferentes, use trava / barreiras. Você também pode obter os resultados parciais até que todos eles terminem usando CompletionService .

Na Java Concurrency na prática: "Se você tem um lote de cálculos a enviar a um Executor e deseja recuperar os resultados à medida que eles se tornam disponíveis, você pode reter o Futuro associado a cada tarefa e pesquisar repetidamente a conclusão, chamando get com um tempo limite de zero. Isso é possível, mas tedioso . Felizmente, existe uma maneira melhor : um serviço de conclusão ".

Aqui a implementação

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());
        }
    }
}
Alberto Gurrion
fonte
3

Esta é a minha solução, baseada na dica "AdamSkywalker", e funciona

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();
    }
}
frss-soft.com
fonte
2

Você pode usar este código:

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");
Tuan Pham
fonte
2

Eu criei o seguinte exemplo de trabalho. A idéia é ter uma maneira de processar um conjunto de tarefas (estou usando uma fila como exemplo) com muitos Threads (determinados programaticamente pelo número de Tarefas / limite) e aguardar até que todos os Threads sejam concluídos para continuar com outro processamento.

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();
        }
    }
}
}

Espero que ajude!

Fernando Gil
fonte
1

Você pode usar sua própria subclasse de ExecutorCompletionService para quebrar taskExecutore sua própria implementação do BlockingQueue para ser informado quando cada tarefa for concluída e executar qualquer retorno de chamada ou outra ação que você desejar quando o número de tarefas concluídas atingir o objetivo desejado.

Alex Martelli
fonte
1

você deve usar executorService.shutdown()e executorService.awaitTerminationmétodo.

Um exemplo da seguinte maneira:

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);
    }

}
Rollen Holt
fonte
é waititTermination () necessário após o desligamento () /
gaurav
1

Então, eu posto minha resposta da pergunta vinculada aqui, caso alguém queira uma maneira mais simples de fazer isso

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.
Mạnh Quyết Nguyễn
fonte
0

Java 8 - Podemos usar a API de fluxo para processar o fluxo. Veja o snippet abaixo

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();
Vlad
fonte
2
Olá Vlad, bem-vindo ao StackOverflow. Você pode editar sua resposta para explicar como isso responde à pergunta e o que o código faz? As respostas somente de código são desencorajadas aqui. Obrigado!
Tim Malone
Este post fala sobre simultaneidade. Parallelism! = Concurrency
GabrielBB 30/08/19
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();

Se doSomething()lançar outras exceções, a latch.countDown()aparência não será executada, então o que devo fazer?

Pengfei Zhan
fonte
0

se você usar mais encadeamentos ExecutionServices SEQUENCIALMENTE e desejar esperar que CADA EXECUTIONSERVICE seja concluído. A melhor maneira é como abaixo;

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){
 ...
}
Dr. X
fonte
-1

Isso pode ajudar

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) {}
            }
Amol Desai
fonte
-1

Você pode chamar waitTillDone () nesta 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

Você pode reutilizar essa classe e chamar waitTillDone () quantas vezes quiser antes de chamar shutdown (), além de seu código ser extremamente simples . Além disso, você não precisa saber o número de tarefas antecipadamente.

Para usá-lo basta adicionar este gradle / maven compile 'com.github.matejtymes:javafixes:1.3.1' dependência ao seu projeto.

Mais detalhes podem ser encontrados aqui:

https://github.com/MatejTymes/JavaFixes

Matej Tymes
fonte
-2

Existe um método no executor getActiveCount()- que fornece a contagem de threads ativos.

Após estender o segmento, podemos verificar se o activeCount()valor é 0. Quando o valor é zero, significa que não há threads ativos em execução no momento, o que significa que a tarefa foi concluída:

while (true) {
    if (executor.getActiveCount() == 0) {
    //ur own piece of code
    break;
    }
}
do utilizador
fonte
3
Não é uma boa ideia, consulte stackoverflow.com/a/7271685/1166992 e o javadoc: "Retorna o número aproximado de threads que estão executando tarefas ativamente".
Olivier Faucheux