ExecutorService - čaká sa na dokončenie vlákien

1. Prehľad

The ExecutorService rámec uľahčuje spracovanie úloh vo viacerých vláknach. Ukážeme príklady niektorých scenárov, v ktorých čakáme na ukončenie vykonávania vlákien.

Tiež si ukážeme, ako elegantne vypnúť program ExecutorService a počkajte, kým už spustené vlákna dokončia svoje vykonávanie.

2. Po Exekútor Vypnúť

Pri použití Exekútor, môžeme to vypnúť zavolaním na vypnúť() alebo shutdownNow () metódy. Aj keď to nebude čakať, kým sa všetky vlákna prestanú vykonávať.

Čakanie na dokončenie vykonávania existujúcich vlákien sa dá dosiahnuť použitím awaitTermination () metóda.

Toto blokuje vlákno, kým všetky úlohy nedokončia svoje vykonanie alebo kým nedosiahne určený časový limit:

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

3. Používanie CountDownLatch

Ďalej sa pozrime na ďalší prístup k riešeniu tohto problému - pomocou a CountDownLatch signalizovať splnenie úlohy.

Môžeme ho inicializovať hodnotou, ktorá predstavuje počet opakovaní, ktoré je možné znížiť pred všetkými vláknami, ktoré volali čakať () sú informovaní.

Napríklad, ak potrebujeme, aby súčasné vlákno čakalo na ďalšie N závity na dokončenie ich vykonania, môžeme zámok inicializovať pomocou N:

ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool (10); Západka CountDownLatch = nová CountDownLatch (2); for (int i = 0; i {try {// ... latch.countDown ();} catch (InterruptedException e) {Thread.currentThread (). interrupt ();}}); } // čakať na zníženie západky o dve zvyšné vlákna latch.await ();

4. Používanie invokeAll ()

Prvý prístup, ktorý môžeme použiť na spustenie vlákien, je invokeAll () metóda. Metóda vráti zoznam Budúcnosť objekty po dokončení všetkých úloh alebo po uplynutí časového limitu.

Musíme tiež poznamenať, že poradie vrátených Budúcnosť objektov je rovnaký ako zoznam poskytovaných Vyvolávateľná objekty:

ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool (10); Zoznam callables = Arrays.asList (nový DelayedCallable ("rýchle vlákno", 100), nový DelayedCallable ("pomalé vlákno", 3000)); long startProcessingTime = System.currentTimeMillis (); Zoznam futures = WORKER_THREAD_POOL.invokeAll (volané čísla); awaitTerminationAfterShutdown (WORKER_THREAD_POOL); long totalProcessingTime = System.currentTimeMillis () - startProcessingTime; assertTrue (totalProcessingTime> = 3000); Reťazec firstThreadResponse = futures.get (0) .get (); assertTrue ("rýchle vlákno" .equals (firstThreadResponse)); Reťazec secondThreadResponse = futures.get (1) .get (); assertTrue ("pomalé vlákno" .equals (secondThreadResponse));

5. Používanie ExecutorCompletionService

Ďalším prístupom k spusteniu viacerých vlákien je použitie ExecutorCompletionService. Používa dodávané ExecutorService vykonávať úlohy.

Jeden rozdiel nad invokeAll () je poradie, v ktorom Futures, zastupujúce vykonané úlohy sa vrátia. ExecutorCompletionService použije rad na uloženie výsledkov v poradí, v akom sú hotové, zatiaľ čo invokeAll () vráti zoznam s rovnakým postupným poradím, aký vytvoril iterátor pre daný zoznam úloh:

Služba CompletionService = nový ExecutorCompletionService (WORKER_THREAD_POOL); Zoznam callables = Arrays.asList (nový DelayedCallable ("rýchle vlákno", 100), nový DelayedCallable ("pomalé vlákno", 3000)); for (Callable callable: callables) {service.submit (callable); } 

Výsledky sú prístupné pomocou vziať () metóda:

long startProcessingTime = System.currentTimeMillis (); Budúca budúcnosť = service.take (); Reťazec firstThreadResponse = future.get (); long totalProcessingTime = System.currentTimeMillis () - startProcessingTime; assertTrue ("Prvá odpoveď by mala byť z rýchleho vlákna", "rýchle vlákno" .equals (firstThreadResponse)); assertTrue (totalProcessingTime> = 100 && totalProcessingTime = 3000 && totalProcessingTime <4000); LOG.debug ("Vlákno skončené po:" + totalProcessingTime + "milisekundy"); awaitTerminationAfterShutdown (WORKER_THREAD_POOL);

6. Záver

V závislosti od prípadu použitia máme rôzne možnosti čakania na dokončenie vykonávania vlákien.

A CountDownLatch je užitočné, keď potrebujeme mechanizmus, ktorý upozorní jedno alebo viac vlákien na to, že skupina operácií vykonávaných inými vláknami skončila.

ExecutorCompletionService je užitočné, keď potrebujeme získať čo najskôr výsledok úlohy a iné prístupy, keď chceme počkať na dokončenie všetkých spustených úloh.

Zdrojový kód článku je k dispozícii na GitHub.


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