ExecutorService - Čekanje da se niti završe

1. Pregled

The ExecutorService framework olakšava obradu zadataka u više niti. Ilustrirat ćemo neke scenarije u kojima čekamo da niti dovrše svoje izvršavanje.

Također ćemo pokazati kako se elegantno isključuje ExecutorService i pričekajte da već pokrenute niti završe svoje izvršavanje.

2. Poslije Izvršiteljeva Ugasiti

Kada koristite Izvršitelj, možemo ga isključiti pozivom na ugasiti() ili shutdownNow () metode. Iako, neće pričekati dok se sve niti ne prestanu izvršavati.

Čekanje da postojeće niti dovrše svoje izvršavanje može se postići korištenjem awaitTermination () metoda.

To blokira nit dok svi zadaci ne dovrše izvršenje ili dok se ne dosegne određeno vremensko ograničenje:

javna praznina awaitTerminationAfterShutdown (ExecutorService threadPool) {threadPool.shutdown (); probajte {if (! threadPool.awaitTermination (60, TimeUnit.SECONDS)) {threadPool.shutdownNow (); }} catch (InterruptedException ex) {threadPool.shutdownNow (); Thread.currentThread (). Interrupt (); }}

3. Korištenje CountDownLatch

Dalje, pogledajmo još jedan pristup rješavanju ovog problema - pomoću a CountDownLatch da signalizira završetak zadatka.

Možemo ga inicijalizirati vrijednošću koja predstavlja koliko se puta može dekrementirati prije svih niti koje su pozvale čekati() metoda, su obaviješteni.

Na primjer, ako trebamo trenutnu nit da bismo pričekali drugu N niti da bi dovršili njihovo izvršenje, možemo inicijalizirati zasun pomoću N:

ExecutorService WORKER_THREAD_POOL = Izvršitelji.newFixedThreadPool (10); Zasun CountDownLatch = novi CountDownLatch (2); for (int i = 0; i {try {// ... latch.countDown ();} catch (InterruptedException e) {Thread.currentThread (). interrupt ();}}); } // čekati da se zasun smanji s dvije preostale niti latch.await ();

4. Korištenje invokeAll ()

Prvi pristup koji možemo koristiti za pokretanje niti je invokeAll () metoda. Metoda vraća popis Budućnost objekata nakon završetka svih zadataka ili isteka vremenskog ograničenja.

Također, moramo napomenuti da je redoslijed vraćenih Budućnost objekata jednak je popisu ponuđenih Pozivno objekti:

ExecutorService WORKER_THREAD_POOL = Izvršitelji.newFixedThreadPool (10); Popis callables = Arrays.asList (novi DelayedCallable ("brza nit", 100), novi DelayedCallable ("spora nit", 3000)); long startProcessingTime = System.currentTimeMillis (); Popis futures = WORKER_THREAD_POOL.invokeAll (pozivi); awaitTerminationAfterShutdown (WORKER_THREAD_POOL); long totalProcessingTime = System.currentTimeMillis () - startProcessingTime; assertTrue (totalProcessingTime> = 3000); String firstThreadResponse = futures.get (0) .get (); assertTrue ("brza nit" .equals (firstThreadResponse)); Niz secondThreadResponse = futures.get (1) .get (); assertTrue ("spora nit" .equals (secondThreadResponse));

5. Korištenje ExecutorCompletionService

Sljedeći pristup izvođenju više niti je korištenje ExecutorCompletionService. Koristi isporučeni ExecutorService za izvršavanje zadataka.

Jedna razlika gotova invokeAll () je redoslijed kojim se Budućnosti, koji predstavljaju izvršene zadatke vraćaju se. ExecutorCompletionService koristi red za spremanje rezultata onim redoslijedom kojim su gotovi, dok invokeAll () vraća popis s istim sekvencijalnim redoslijedom koji je izradio iterator za zadani popis zadataka:

Usluga CompletionService = novi ExecutorCompletionService (WORKER_THREAD_POOL); Popis callables = Arrays.asList (novi DelayedCallable ("brza nit", 100), novi DelayedCallable ("spora nit", 3000)); za (Callable callable: callables) {service.submit (callable); } 

Rezultatima se može pristupiti pomoću uzeti() metoda:

long startProcessingTime = System.currentTimeMillis (); Buduća budućnost = service.take (); String firstThreadResponse = future.get (); long totalProcessingTime = System.currentTimeMillis () - startProcessingTime; assertTrue ("Prvi odgovor trebao bi biti iz brze niti", "brza nit" .equals (firstThreadResponse)); assertTrue (totalProcessingTime> = 100 && totalProcessingTime = 3000 && totalProcessingTime <4000); LOG.debug ("Tema je završena nakon:" + totalProcessingTime + "milisekunde"); awaitTerminationAfterShutdown (WORKER_THREAD_POOL);

6. Zaključak

Ovisno o slučaju upotrebe, imamo razne mogućnosti čekanja da niti dovrše svoje izvršavanje.

A CountDownLatch je korisno kada trebamo mehanizam za obavještavanje jedne ili više niti da je skup operacija koje su izvele druge niti završio.

ExecutorCompletionService je korisno kada moramo pristupiti rezultatu zadatka što je prije moguće i drugim pristupima kada želimo pričekati da se svi izvršeni zadaci završe.

Izvorni kôd članka dostupan je na GitHubu.


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