Come attendere il completamento di tutti i thread, utilizzando ExecutorService?


381

Ho bisogno di eseguire un numero di compiti 4 alla volta, qualcosa del genere:

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

Come posso ricevere una notifica una volta completati? Per ora non riesco a pensare a niente di meglio che impostare un contatore di attività globale e ridurlo alla fine di ogni attività, quindi monitorare in loop infinito questo contatore per diventare 0; o ottenere un elenco di Futures e nel monitor a ciclo infinito è Fatto per tutti. Quali sono le soluzioni migliori che non prevedono loop infiniti?

Grazie.

Risposte:


446

Fondamentalmente su una ExecutorServicechiamata shutdown()e quindi 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
questo è esattamente lo scopo di shutdown / awaitTermination
matt b

31
È un buon modello se questa gestione delle attività è un evento singolo. Se questo viene fatto ripetutamente durante lo stesso runtime, tuttavia, non è ottimale, in quanto creeresti e riduresti i thread ripetutamente ogni volta che viene eseguito.
sjlee,

44
Sto cercando qualsiasi documentazione ufficiale che Long.MAX_VALUE, TimeUnit.NANOSECONDSequivale a non avere un timeout.
Sam Harwell,

15
Non riesco a credere che devi usare shutdown per unirti a tutti i thread correnti (dopo aver usato shutdown, non puoi mai più usare l'esecutore). Suggerisci invece di utilizzare un elenco di Future's ...
rogerdpack,

20
@SamHarwell vedere la documentazione del java.util.concurrentpacchetto nella sezione: Per attendere "per sempre", è possibile utilizzare un valore diTimingLong.MAX_VALUE
beluchin

174

Usa un CountDownLatch :

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

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

e nell'ambito dell'attività (allegare in try / finally)

latch.countDown();

3
Non ci sono 4 compiti. Esistono "un certo numero di compiti" eseguiti 4 alla volta.
cletus,

2
Scusa, ho frainteso la domanda. Sì, il numero di attività dovrebbe essere l'argomento del costruttore CountDownLatch
ChssPly76

3
Trovo questa soluzione più elegante delle altre, sembra che sia stata creata per questo scopo ed è semplice e diretta.
wvdschel,

3
Cosa succede se non si conosce il numero di attività prima di iniziare?
cletus,

11
@cletus - allora non usi CountDownLatch :-) Intendiamoci, non sto sostenendo che questo approccio sia migliore del tuo. Tuttavia, ho scoperto che in scenari di vita reale io non conosco il numero di attività, le impostazioni del pool di thread non hanno bisogno di essere configurabile per la distribuzione, e le piscine possono essere riutilizzati. Quindi di solito ho i pool di thread iniettati da Spring e li imposta come prototipi e li spegne manualmente solo per aspettare che i thread finiscano sembra meno che ideale.
ChssPly76,

82

ExecutorService.invokeAll() lo fa per te.

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

La difficoltà arriva se / quando hai l'inizio dei "4" thread uno alla volta, a livello di pezzo, quindi unisciti / lascia finire tutti 4 ...
rogerdpack

@rogerdpack: sto ancora imparando questi esecutori e roba del genere. Ma in risposta a ciò che chiedi. I 4 thread alla volta non dovrebbero far parte di un'attività batch che viene eseguita utilizzando la risposta sopra?
Mukul Goel,

3
Questo metodo funziona solo se si conosce prima il numero di attività.
Konstantin,

3
Penso che quando futuresvengono restituiti, le attività non sono state completate. Potrebbero completarsi in futuro e avrai un link al risultato. Ecco perché si chiama a Future. Hai il metodo Future.get () , che attenderà il completamento dell'attività per ottenere un risultato.
AlikElzin-Kilaka,

5
@ AlikElzin-kilaka Citazione da JavaDocs (collegata nella risposta): "Esegue le attività assegnate, restituendo un elenco di Futures che mantengono il loro stato e risultati quando tutto è completo. Future.isDone () è vero per ogni elemento dell'elenco restituito. "
Hulk,

47

Puoi anche usare Elenchi di 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;
  }
}));

quindi quando vuoi unirti a tutti loro, è essenzialmente l'equivalente di unirli su ciascuno di essi (con l'ulteriore vantaggio di aumentare nuovamente le eccezioni dai thread figlio al principale):

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

Fondamentalmente il trucco è chiamare .get () su ogni Future uno alla volta, invece di chiamare in loop infinito isDone () su (tutto o ciascuno). Quindi sei sicuro di "andare avanti" attraverso e oltre questo blocco non appena termina l'ultimo thread. L'avvertenza è che dal momento che la chiamata .get () aumenta le eccezioni, se uno dei thread muore, potresti sollevare da questo probabilmente prima che gli altri thread abbiano terminato fino al completamento [per evitare ciò, potresti aggiungere un https: // stackoverflow.com/a/31885029/32453catch ExecutionException giro intorno alla chiamata get ]. L'altro avvertimento è che mantiene un riferimento a tutti i thread, quindi se hanno variabili locali di thread non verranno raccolti fino a quando non si supera questo blocco (anche se potresti essere in grado di aggirare questo, se è diventato un problema, rimuovendo Future is off the ArrayList). Se volessi sapere quale futuro "finisce per primo"


3
Per sapere quale "finiture primi", l'uso ExecutorCompletionService.take: stackoverflow.com/a/11872604/199364
ToolmakerSteve

34

In Java8 puoi farlo con 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
Questa è una soluzione molto 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 è awaitTermination () necessario dopo es.shutdown ()?
gaurav,

@gaurav quando si chiama lo spegnimento, alcune attività potrebbero non essere ancora terminate. Quindi waititTermination bloccherà il thread chiamante fino a quando non sarà fatto tutto. Dipende se devi attendere i risultati in questa discussione o meno.
AdamSkywalker,

@AdamSkywalker ottima risposta. ha senso non chiamare waititTermination () se non ho bisogno di aspettare i risultati.
gaurav,

26

Solo i miei due centesimi. Per superare il requisito di CountDownLatchconoscere in anticipo il numero di compiti, è possibile farlo alla vecchia maniera usando un semplice Semaphore.

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

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

Nel tuo compito chiama semplicemente s.release()come farestilatch.countDown();


Vedendo questo, mi sono prima chiesto se sarebbe un problema se alcune releasechiamate accadessero prima della acquirechiamata, ma dopo aver letto la documentazione di Semaphore, vedo che va bene.
ToolmakerSteve

13

Un po 'in ritardo al gioco, ma per motivi di completamento ...

Invece di "aspettare" che tutti i compiti finiscano, puoi pensare in base al principio di Hollywood, "non chiamarmi, ti chiamerò" - quando avrò finito. Penso che il codice risultante sia più elegante ...

Guava offre alcuni strumenti interessanti per raggiungere questo obiettivo.

Un esempio ::

Avvolgere un ExecutorService in un ListeningExecutorService ::

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

Invia una raccolta di callable per l'esecuzione ::

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

Ora la parte essenziale:

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

Allega una richiamata a ListenableFuture, che puoi utilizzare per ricevere una notifica quando tutti i futures sono completi:

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

Ciò offre anche il vantaggio di poter raccogliere tutti i risultati in un unico posto una volta terminata l'elaborazione ...

Maggiori informazioni qui


2
Molto pulito. Funziona perfettamente anche su Android. Basta dovuto usare runOnUiThread()in onSuccess().
DSchmidt,

12

La classe CyclicBarrier in Java 5 e successive è progettata per questo genere di cose.


7
Fantastico, non ricordo mai il nome di questa struttura di dati. Tuttavia, è adatto solo se si conosce in anticipo la quantità di attività che verranno messe in coda.
ᆼ ᆺ ᆼ

sì, penseresti che saresti in grado di colpire la barriera con il thread corrente e tutti i thread figlio, quindi quando lo hai passato sapresti che i thread figlio sono stati fatti ...
rogerdpack

In realtà è una risposta sbagliata. CyclicBarrier progettato per porzioni. CountDownLatch progettato per l'evento in attesa
gstackoverflow,

7

Segui uno degli approcci seguenti.

  1. Scorrere tutti i futuri compiti, tornati da submitsu ExecutorServicee controllare lo stato di blocco di chiamata get()in Futureoggetto come suggerito daKiran
  2. Utilizzare invokeAll()su ExecutorService
  3. CountDownLatch
  4. ForkJoinPool o Executors.html # newWorkStealingPool
  5. Utilizzare le shutdown, awaitTermination, shutdownNowAPI di ThreadPoolExecutor nella sequenza corretta

Domande SE correlate:

Come viene utilizzato CountDownLatch nel multithreading Java?

Come arrestare correttamente java ExecutorService


6

qui ci sono due opzioni, solo un po 'confondere quale è meglio andare.

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

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

Qui mettendo future.get (); in prova cattura è una buona idea vero?


5

È possibile racchiudere le attività in un altro eseguibile, che invierà notifiche:

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

1
Mi ci è voluto un po 'per vedere come questo avrebbe risolto la domanda di OP. Innanzitutto, si noti che questo wrapping riguarda ciascuna attività, non il codice che avvia tutte le attività. Presumibilmente, ogni inizio incrementerebbe un contatore e ogni fine decrementerebbe quel contatore o incrementerebbe un completedcontatore. Quindi, dopo averli avviati tutti, ad ogni notifica, è possibile determinare se tutte le attività sono state completate. Si noti che è fondamentale utilizzare in try/finallymodo che catchvenga data una notifica finita (o una notifica alternativa in blocco) anche se un'attività non riesce. Altrimenti, aspetterebbe per sempre.
ToolmakerSteve

3

Ho appena scritto un programma di esempio che risolve il tuo problema. Non è stata fornita un'implementazione concisa, quindi ne aggiungerò una. Sebbene tu possa usare executor.shutdown()e executor.awaitTermination(), non è la migliore pratica in quanto il tempo impiegato da diversi thread sarebbe imprevedibile.

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

È bene che mostri l'uso di future.get: una buona alternativa da conoscere. Ma perché pensi che sia meglio aspettare per sempre , piuttosto che impostare un timeout massimo accettabile? Ancora più importante, non vi è alcun motivo per fare tutta questa logica, quando si può semplicemente dedicare molto, davvero molto tempo per attendere la conclusione, se si desidera attendere (essenzialmente per sempre) fino al completamento di tutte le attività.
ToolmakerSteve

Questo non è diverso dalle soluzioni già presentate qui. La tua giusta soluzione è la stessa presentata da @sjlee
pulp_fiction il

Non sono sicuro del motivo per cui è necessario verificare che sia fatto quando, secondo l'oracle doc, invokeAll restituirà solo "quando tutto è completo o il timeout scade, a seconda di quale
evento si

3

Giusto per fornire più alternative qui diverse da usare latch / barriere. Puoi anche ottenere i risultati parziali fino a quando tutti non finiscono di utilizzare CompletionService .

Dalla concorrenza Java in pratica: "Se si dispone di un batch di calcoli da inviare a un Executor e si desidera recuperare i loro risultati non appena disponibili, è possibile conservare il Future associato a ciascuna attività e ripetere il polling ripetutamente per il completamento chiamando get with a timeout pari a zero. Questo è possibile, ma noioso . Fortunatamente esiste un modo migliore : un servizio di completamento ".

Qui l'implementazione

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

Questa è la mia soluzione, basata sul suggerimento "AdamSkywalker", e funziona

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

Puoi usare questo codice:

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

Ho creato il seguente esempio di lavoro. L'idea è di avere un modo per elaborare un pool di attività (sto usando una coda come esempio) con molti thread (determinati a livello di programmazione dal numero di attività / soglia) e attendere che tutti i thread siano completati per continuare con qualche altra elaborazione.

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

Spero che sia d'aiuto!


1

È possibile utilizzare la propria sottoclasse di ExecutorCompletionService per concludere taskExecutore la propria implementazione di BlockingQueue per essere informati quando ogni attività viene completata ed eseguire qualsiasi richiamata o altra azione desiderata quando il numero di attività completate raggiunge l'obiettivo desiderato.


1

dovresti usare executorService.shutdown()e executorService.awaitTerminationmetodo.

Un esempio come segue:

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

}

è awaitTermination () necessario dopo shutdown () /
gaurav l'

1

Quindi inserisco la mia risposta dalla domanda collegata qui, nel caso qualcuno voglia un modo più semplice per farlo

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: possiamo usare l'API stream per elaborare lo stream. Si prega di consultare lo snippet di seguito

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
Ciao Vlad, benvenuto su StackOverflow. Puoi per favore modificare la tua risposta per spiegare come questo risponde alla domanda e cosa fa il codice? Qui sono sconsigliate solo le risposte al codice. Grazie!
Tim Malone,

Questo post parla di concorrenza. Parallelismo! = Concorrenza
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();

Se si doSomething()generano alcune altre eccezioni, latch.countDown()sembra che non verrà eseguito, quindi cosa devo fare?


0

se si utilizzano più thread ExecutionServices SEQUENZIALMENTE e si desidera attendere il completamento di OGNI EXECUTIONSERVICE. Il modo migliore è come sotto;

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

Questo potrebbe aiutare

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

Puoi chiamare waitTillDone () su questa 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

Puoi riutilizzare questa classe e chiamare waitTillDone () tutte le volte che vuoi prima di chiamare shutdown (), inoltre il tuo codice è estremamente semplice . Inoltre non è necessario conoscere il numero di attività anticipo.

Per usarlo basta aggiungere questo gradle / maven compile 'com.github.matejtymes:javafixes:1.3.1' dipendenza al tuo progetto.

Maggiori dettagli possono essere trovati qui:

https://github.com/MatejTymes/JavaFixes


-2

Esiste un metodo nell'esecutore getActiveCount()che fornisce il conteggio dei thread attivi.

Dopo aver attraversato il thread, possiamo verificare se il activeCount()valore è 0. Una volta che il valore è zero, significa che non ci sono thread attivi attualmente in esecuzione, il che significa che l'attività è terminata:

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

3
Non è una buona idea, vedi stackoverflow.com/a/7271685/1166992 e javadoc: "Restituisce il numero approssimativo di thread che eseguono attivamente attività".
Olivier Faucheux il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.