ExecutorService - Venter på at tråder skal fullføres

1. Oversikt

De ExecutorService rammeverk gjør det enkelt å behandle oppgaver i flere tråder. Vi skal eksemplifisere noen scenarier der vi venter på at tråder skal fullføres.

Vi vil også vise hvordan du kan slå av en elegant ExecutorService og vent på at trådene som allerede er i gang, skal fullføres.

2. Etter Lederens Skru av

Når du bruker en Utøvende vi kan stenge den ved å ringe skru av() eller shutdownNow () metoder. Selv om det ikke vil vente til alle tråder slutter å kjøres.

Å vente på at eksisterende tråder skal fullføres, kan oppnås ved å bruke awaitTermination () metode.

Dette blokkerer tråden til alle oppgaver fullfører kjøringen eller den angitte tidsavbruddet er nådd:

offentlig tomrom awaitTerminationAfterShutdown (ExecutorService threadPool) {threadPool.shutdown (); prøv {if (! threadPool.awaitTermination (60, TimeUnit.SECONDS)) {threadPool.shutdownNow (); }} fange (InterruptedException ex) {threadPool.shutdownNow (); Thread.currentThread (). Interrupt (); }}

3. Bruke CountDownLatch

Deretter, la oss se på en annen tilnærming til å løse dette problemet - ved hjelp av a CountDownLatch for å signalisere fullføringen av en oppgave.

Vi kan initialisere den med en verdi som representerer antall ganger den kan reduseres før alle tråder som har kalt avvente() metode, blir varslet.

For eksempel hvis vi trenger den gjeldende tråden for å vente på en annen N tråder for å fullføre utførelsen, kan vi initialisere låsen ved hjelp av N:

ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool (10); CountDownLatch latch = ny CountDownLatch (2); for (int i = 0; i {try {// ... latch.countDown ();} catch (InterruptedException e) {Thread.currentThread (). interrupt ();}}); } // vent på at låsen blir dekrementert av de to gjenværende trådene latch.await ();

4. Bruke påkalleAll ()

Den første tilnærmingen som vi kan bruke til å kjøre tråder er påkalleAll () metode. Metoden returnerer en liste over Framtid objekter etter at alle oppgaver er ferdig eller tidsavbruddet utløper.

Vi må også merke oss at rekkefølgen på den returnerte Framtid objekter er den samme som listen over Kan kalles gjenstander:

ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool (10); Liste callables = Arrays.asList (new DelayedCallable ("fast thread", 100), new DelayedCallable ("slow thread", 3000)); lang startProcessingTime = System.currentTimeMillis (); Liste futures = WORKER_THREAD_POOL.invokeAll (callables); awaitTerminationAfterShutdown (WORKER_THREAD_POOL); lang totalProcessingTime = System.currentTimeMillis () - startProcessingTime; assertTrue (totalProcessingTime> = 3000); Streng firstThreadResponse = futures.get (0) .get (); assertTrue ("rask tråd" .equals (firstThreadResponse)); Streng secondThreadResponse = futures.get (1) .get (); assertTrue ("slow thread" .equals (secondThreadResponse));

5. Bruke ExecutorCompletionService

En annen tilnærming til å kjøre flere tråder er ved å bruke ExecutorCompletionService. Den bruker en levert ExecutorService å utføre oppgaver.

En forskjell over påkalleAll () er i hvilken rekkefølge Fremtid, som representerer de utførte oppgavene, returneres. ExecutorCompletionService bruker en kø for å lagre resultatene i den rekkefølgen de er ferdige, samtidig som påkalleAll () returnerer en liste med samme rekkefølge som produsert av iteratoren for den gitte oppgavelisten:

CompletionService-tjeneste = ny ExecutorCompletionService (WORKER_THREAD_POOL); Liste callables = Arrays.asList (new DelayedCallable ("fast thread", 100), new DelayedCallable ("slow thread", 3000)); for (Callable callable: callables) {service.submit (callable); } 

Resultatene kan nås ved hjelp av ta() metode:

lang startProcessingTime = System.currentTimeMillis (); Fremtidig fremtid = service.take (); Streng firstThreadResponse = future.get (); lang totalProcessingTime = System.currentTimeMillis () - startProcessingTime; assertTrue ("Første svar skal være fra den raske tråden", "rask tråd" .equals (firstThreadResponse)); assertTrue (totalProcessingTime> = 100 && totalProcessingTime = 3000 && totalProcessingTime <4000); LOG.debug ("Tråden ferdig etter:" + totalProcessingTime + "millisekunder"); awaitTerminationAfterShutdown (WORKER_THREAD_POOL);

6. Konklusjon

Avhengig av brukssaken, har vi forskjellige muligheter for å vente på at tråder skal fullføres.

EN CountDownLatch er nyttig når vi trenger en mekanisme for å varsle en eller flere tråder som et sett med operasjoner utført av andre tråder er ferdig.

ExecutorCompletionService er nyttig når vi trenger tilgang til oppgavens resultat så snart som mulig og andre tilnærminger når vi vil vente på at alle løpende oppgaver er ferdige.

Kildekoden for artikkelen er tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found