CodeGym /Java tanfolyam / /ExecutorService felület

ExecutorService felület

Szint , Lecke
Elérhető

Miért van szüksége az Executor felületre?

A Java 5 előtt az összes saját kódszál-kezelést be kellett írnia az alkalmazásba. Emellett létrehozva aúj témaAz objektum erőforrás-igényes művelet, és nincs értelme minden könnyű feladathoz új szálat létrehozni. És mivel ez a probléma abszolút minden többszálas alkalmazások fejlesztője számára ismerős, úgy döntöttek, hogy végrehajtják a Java-ban ezt a funkciót Executor keretrendszerként.

Mi a nagy ötlet? Egyszerű: ahelyett, hogy minden új feladathoz új szálat hoznánk létre, a szálak egyfajta „tárhelyen” vannak tárolva, és amikor új feladat érkezik, új létrehozása helyett egy meglévő szálat kérünk le.

Ennek a keretrendszernek a fő felületei az Executor , az ExecutorService és a ScheduledExecutorService , amelyek mindegyike kiterjeszti az előző funkcionalitását.

Az Executor felület az alap interfész. Egyetlen void execute (Futtatható parancs) metódust deklarál , amelyet egy futtatható objektum valósít meg .

Az ExecutorService felület érdekesebb. Módszerei vannak a munka befejezésének kezelésére, valamint módszerek valamilyen eredmény visszaadására. Nézzük meg közelebbről a módszereit:

Módszer Leírás
void shutdown(); A metódus meghívása leállítja az ExecutorService-t . A már feldolgozásra leadott összes feladat elvégzésre kerül, de új feladatokat nem fogadunk el.
Lista<Futtatható> shutdownNow();

A metódus meghívása leállítja az ExecutorService-t . A Thread.interrupt minden olyan feladat esetén meghívásra kerül, amelyet már feldolgozásra elküldtek. Ez a metódus a sorban álló feladatok listáját adja vissza.

A metódus nem várja meg az összes olyan feladat befejezését, amely a metódus meghívásakor "folyamatban van".

Figyelmeztetés: Ennek a metódusnak a meghívásával források szivároghatnak ki.

logikai isShutdown(); Ellenőrzi, hogy az ExecutorService le van-e állítva.
logikai isTerminated(); Igaz értéket ad vissza, ha az ExecutorService leállítása után minden feladat befejeződött . Amíg a shutdown() vagy shutdownNow() meg nem hívjuk, mindig false értéket ad vissza .
boolean awaitTermination (hosszú időtúllépés, TimeUnit egység) InterruptedExceptiont dob;

A shutdown() metódus meghívása után ez a metódus blokkolja azt a szálat, amelyen meghívásra került, amíg a következő feltételek egyike nem teljesül:

  • minden ütemezett feladat befejeződött;
  • a metódusnak átadott időtúllépés lejárt;
  • az aktuális szál megszakad.

Igaz értéket ad vissza , ha minden feladat befejeződött, és hamis értéket , ha az időtúllépés letelik a befejezés előtt.

<T> Future<T> submit(Hívható<T> feladat);

Hozzáad egy hívható feladatot az ExecutorService- hez , és visszaad egy objektumot, amely megvalósítja a Future felületet.

A <T> az átadott feladat eredményének típusa.

<T> Future<T> submit(Futtatható feladat, T eredmény);

Hozzáad egy futtatható feladatot az ExecutorService- hez , és visszaad egy objektumot, amely megvalósítja a Future felületet.

A T eredmény paraméter az, amit a get() metódus hívása visszaad az eredményülJövő tárgya.

Future<?> submit(Futtatható feladat);

Hozzáad egy futtatható feladatot az ExecutorService- hez , és visszaad egy objektumot, amely megvalósítja a Future felületet.

Ha a kapott Future objektumon meghívjuk a get() metódust , akkor nullát kapunk.

<T> List<Jövő<T>> invokeAll(Gyűjtemény<? kiterjeszti a Hívható<T>> feladatokat) InterruptedException;

A hívható feladatok listáját átadja az ExecutorService- nek . Visszaadja a Futures listát, amelyből megkaphatjuk a munka eredményét. Ez a lista akkor jelenik meg, amikor az összes beküldött feladatot befejezte.

Ha a feladatgyűjtemény módosul a metódus futása közben, akkor ennek a metódusnak az eredménye nincs meghatározva.

<T> Lista<Jövő<T>> invokeAll(Gyűjtemény<? kiterjeszti a hívható<T>> feladatokat, hosszú időtúllépés, TimeUnit egység) InterruptedException;

A hívható feladatok listáját átadja az ExecutorService- nek . Visszaadja a Futures listát, amelyből megkaphatjuk a munka eredményét. Ez a lista akkor jelenik meg, amikor az összes átadott feladat befejeződött, vagy a metódusnak átadott időtúllépés lejárta után, attól függően, hogy melyik következik be előbb.

Ha az időkorlát letelik, a befejezetlen feladatok törlődnek.

Megjegyzés: Lehetséges, hogy a törölt feladat futása nem áll le (a példában ezt a mellékhatást fogjuk látni).

Ha a feladatgyűjtemény módosul a metódus futása közben, akkor ennek a metódusnak az eredménye nincs meghatározva.

<T> T invokeAny(Collection<? expands Callable<T>> task) dob InterruptedException, ExecutionException;

A hívható feladatok listáját átadja az ExecutorService- nek . Az egyik olyan feladat eredményét adja vissza (ha van), amelyet kivétel nélkül teljesítettek (ha van ilyen).

Ha a feladatgyűjtemény módosul a metódus futása közben, akkor ennek a metódusnak az eredménye nincs meghatározva.

<T> T invokeAny(Gyűjtemény<? kiterjeszti a Hívható<T>> feladatokat, hosszú időtúllépés, TimeUnit egység) InterruptedException, ExecutionException, TimeoutException;

A hívható feladatok listáját átadja az ExecutorService- nek . Az egyik olyan feladat eredményét adja vissza (ha van), amely kivétel nélkül fejeződött be, mielőtt a metódusnak adott időtúllépés lejárt volna.

Ha a feladatgyűjtemény módosul a metódus futása közben, akkor ennek a metódusnak az eredménye nincs meghatározva.

Nézzünk egy kis példát az ExecutorService szolgáltatással való együttműködésre .


import java.util.List;
import java.util.concurrent.*;

public class ExecutorServiceTest {
   public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
//Create an ExecutorService for 2 threads
       java.util.concurrent.ExecutorService executorService = new ThreadPoolExecutor(2, 2, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
// Create 5 tasks
       MyRunnable task1 = new MyRunnable();
       MyRunnable task2 = new MyRunnable();
       MyRunnable task3 = new MyRunnable();
       MyRunnable task4 = new MyRunnable();
       MyRunnable task5 = new MyRunnable();

       final List<MyRunnable> tasks = List.of(task1, task2, task3, task4, task5);
// Pass a list that contains the 5 tasks we created
       final List<Future<Void>> futures = executorService.invokeAll(tasks, 6, TimeUnit.SECONDS);
       System.out.println("Futures received");

// Stop the ExecutorService
       executorService.shutdown();

       try {
           TimeUnit.SECONDS.sleep(3);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println(executorService.isShutdown());
       System.out.println(executorService.isTerminated());
   }

   public static class MyRunnable implements Callable<Void> {

       @Override
       public void call() {
// Add 2 delays. When the ExecutorService is stopped, we will see which delay is in progress when the attempt is made to stop execution of the task
           try {
               TimeUnit.SECONDS.sleep(3);
           } catch (InterruptedException e) {
               System.out.println("sleep 1: " + e.getMessage());
           }
           try {
               TimeUnit.SECONDS.sleep(2);
           } catch (InterruptedException e) {
               System.out.println("sleep 2: " + e.getMessage());
           }
           System.out.println("done");
           return null;
       }
   }
}

Kimenet:

kész
kész
Határidős fogadott
alvás 1: alvás megszakítva
alvás 1: alvás megszakítva
kész
kész igaz
igaz

Minden feladat 5 másodpercig fut. Létrehoztunk egy készletet két szál számára, így a kimenet első két sora teljesen logikus.

Hat másodperccel a program indítása után az invokeAll metódus időtúllépése következik be, és az eredmény a Futures listájaként jelenik meg . Ez látható a Futures kapott kimeneti karakterláncból .

Az első két feladat elvégzése után újabb kettő kezdődik. De mivel az invokeAll metódusban beállított időkorlát letelik, ennek a két feladatnak nincs ideje befejezni. „Mégse” parancsot kapnak . Ez az oka annak, hogy a kimenetnek két sora van alvás 1-el: alvás megszakítva .

És akkor még két sort láthat a done mellett . Ez az a mellékhatás, amelyet az invokeAll metódus leírásakor említettem .

Az ötödik, egyben utolsó feladat el sem indul, így a kimenetben nem látunk róla semmit.

Az utolsó két sor az isShutdown és isTerminated metódusok meghívásának eredménye .

Az is érdekes, hogy ezt a példát hibakeresési módban futtatjuk, és megnézzük a feladat állapotát az időkorlát letelte után (állítsunk be egy töréspontot a sorban az executorService.shutdown(); ) paranccsal:

Azt látjuk, hogy két feladat normálisan befejeződött , és három feladat „törölve” lett .

ScheduledExecutorService

A végrehajtókról szóló vitánk befejezéseként vessünk egy pillantást a ScheduledExecutorService oldalra .

4 módszere van:

Módszer Leírás
public ScheduledFuture<?> ütemterv (Futtatható parancs, hosszú késleltetés, TimeUnit egység); Ütemezi az átadott futtatható feladat egyszeri futtatását az argumentumként megadott késleltetés után.
public <V> ScheduledFuture<V> menetrend(Hívható<V> hívható, hosszú késleltetés, Időegység egység); Ütemezi az átadott hívható feladat egyszeri futását az argumentumként megadott késleltetés után.
public ScheduledFuture<?> scheduleAtFixedRate(Futtatható parancs, hosszú kezdetiKésleltetés, hosszú periódus, Időegység egység); Ütemezi az átadott feladat időszakos végrehajtását, amely először a inicialDelay után kerül végrehajtásra, és minden további futtatás a period után kezdődik .
public ScheduledFuture<?> scheduleWithFixedDelay(Futtatható parancs, hosszú kezdeti késleltetés, hosszú késleltetés, időegység egység); Ütemezi az átadott feladat időszakos végrehajtását, amely először az inicialDelay után kerül végrehajtásra, és minden további futás késleltetés után kezdődik (az előző futás befejezése és az aktuális indítása közötti időszak).
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION