ExecutorService - Várakozás a szálak befejezésére

1. Áttekintés

A ExecutorService keretrendszer megkönnyíti a feladatok több szálon történő feldolgozását. Példákat mutatunk be néhány olyan helyzetre, amelyekben megvárjuk, amíg a szálak befejezik a végrehajtásukat.

Ezenkívül megmutatjuk, hogyan kell kecsesen kikapcsolni egy ExecutorService és várja meg, amíg a már futó szálak befejezik a végrehajtásukat.

2. Utána Végrehajtó Leállitás

Ha egy Végrehajtó, leállíthatjuk a Leállitás() vagy shutdownNow () mód. Bár nem vár, amíg az összes szál leállítja a végrehajtást.

A. Használatával megvárhatjuk, hogy a meglévő szálak befejezzék a végrehajtásukat awaitTermination () módszer.

Ez blokkolja a szálat, amíg az összes feladat befejezi a végrehajtását, vagy el nem éri a megadott időkorlátot:

public void awaitTerminationAfterShutdown (ExecutorService threadPool) {threadPool.shutdown (); próbáld ki a {if (! threadPool.awaitTermination (60, TimeUnit.SECONDS)) {threadPool.shutdownNow (); }} catch (InterruptedException ex) {threadPool.shutdownNow (); Thread.currentThread (). Megszakítás (); }}

3. Használata CountDownLatch

Ezután nézzünk meg egy másik megközelítést a probléma megoldására - az a használatával CountDownLatch jelezni egy feladat befejezését.

Inicializálhatjuk egy értékkel, amely azt mutatja, hogy hányszor lehet csökkenteni minden szál előtt, amelyek a várják() módszerrel.

Például, ha szükségünk van az aktuális szálra egy másik megvárására N szálak végrehajtásának befejezéséhez inicializálhatjuk a reteszt N:

ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool (10); CountDownLatch retesz = new CountDownLatch (2); for (int i = 0; i {próbáld {// ... latch.countDown ();} catch (InterruptedException e) {Thread.currentThread (). megszakítás ();}}); } // várja meg, hogy a retesz csökkenjen a két megmaradt szál által latch.await ();

4. Használata invokeAll ()

Az első megközelítés, amelyet szálak futtatására használhatunk, a invokeAll () módszer. A metódus visszaadja a Jövő objektumok az összes feladat befejezése vagy az időkorlát lejárta után.

Azt is meg kell jegyeznünk, hogy a sorrend a visszaküldött Jövő objektumok megegyeznek a megadott listával Hívható tárgyak:

ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool (10); Lista callables = Arrays.asList (új DelayedCallable ("gyors szál", 100), új DelayedCallable ("lassú szál", 3000)); long startProcessingTime = System.currentTimeMillis (); Lista határidős = WORKER_THREAD_POOL.invokeAll (hívható); awaitTerminationAfterShutdown (WORKER_THREAD_POOL); long totalProcessingTime = System.currentTimeMillis () - startProcessingTime; assertTrue (totalProcessingTime> = 3000); String firstThreadResponse = futures.get (0) .get (); assertTrue ("gyors szál" .equals (firstThreadResponse)); String secondThreadResponse = futures.get (1) .get (); assertTrue ("lassú szál" .equals (secondThreadResponse));

5. Használata ExecutorCompletionService

A több szál futtatásának másik megközelítése a ExecutorCompletionService. Egy mellékeltet használ ExecutorService feladatok végrehajtására.

Egy különbség van invokeAll () az a sorrend, amelyben a Határidős, a végrehajtott feladatokat reprezentálja. ExecutorCompletionService várólistát használ az eredmények készítésük sorrendjében történő tárolásához, miközben invokeAll () egy listát ad vissza, amelynek sorrendje megegyezik az iterátor által az adott feladatlistával létrehozott sorrenddel:

CompletionService szolgáltatás = új ExecutorCompletionService (WORKER_THREAD_POOL); Lista callables = Arrays.asList (új DelayedCallable ("gyors szál", 100), új DelayedCallable ("lassú szál", 3000)); for (Hívható hívható: hívható) {service.submit (hívható); } 

Az eredmények a vesz() módszer:

long startProcessingTime = System.currentTimeMillis (); Jövő jövő = service.take (); String firstThreadResponse = jövő.get (); long totalProcessingTime = System.currentTimeMillis () - startProcessingTime; assertTrue ("Az első válasznak a gyors szálról kell érkeznie", "gyors szál" .equals (firstThreadResponse)); assertTrue (totalProcessingTime> = 100 && totalProcessingTime = 3000 && totalProcessingTime <4000); LOG.debug ("A szál befejezése után:" + totalProcessingTime + "milliszekundum"); awaitTerminationAfterShutdown (WORKER_THREAD_POOL);

6. Következtetés

A felhasználási esettől függően számos lehetőségünk van arra, hogy megvárjuk a szálak végrehajtásának befejezését.

A CountDownLatch Akkor hasznos, ha egy vagy több szál értesítésére szolgáló mechanizmusra van szükségünk arról, hogy a többi szál által végrehajtott műveletek készen vannak.

ExecutorCompletionService akkor hasznos, amikor a lehető leghamarabb hozzáférnünk kell a feladat eredményéhez, és más megközelítésekhez, amikor várni akarjuk az összes futó feladat befejezését.

A cikk forráskódja elérhető a GitHubon.


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