Aszinkron programozás Java-ban

1. Áttekintés

A nem blokkoló kód írása iránti növekvő igény miatt szükségünk van a kód aszinkron végrehajtásának módjaira.

Ebben az oktatóanyagban megvizsgálunk néhány módot az aszinkron programozás elérésére a Java-ban. Ezenkívül megvizsgálunk néhány Java-könyvtárat, amelyek kézből származó megoldásokat kínálnak.

2. Aszinkron programozás Java-ban

2.1. cérna

Új szálat hozhatunk létre bármely művelet aszinkron végrehajtására. A lambda kifejezések Java 8-ban történő kiadásával tisztább és olvashatóbb.

Hozzunk létre egy új szálat, amely kiszámítja és kinyomtatja a szám faktoriálját:

int szám = 20; Szál newThread = új Szál (() -> {System.out.println ("A" + szám + "tényezője:" + faktoriális (szám));}); newThread.start ();

2.2. FutureTask

A Java 5 óta az Jövő interfész lehetőséget nyújt aszinkron műveletek végrehajtására a FutureTask.

Használhatjuk a Beküldés módszere ExecutorService a feladat aszinkron végrehajtásához és a FutureTask.

Tehát keressük meg egy szám faktoriálját:

ExecutorService threadpool = Executors.newCachedThreadPool (); Future futureTask = threadpool.submit (() -> faktoriális (szám)); while (! futureTask.isDone ()) {System.out.println ("A FutureTask még nem fejeződött be ..."); } hosszú eredmény = futureTask.get (); threadpool.shutdown ();

Itt használtuk a kész módszer által biztosított Jövő felületet, hogy ellenőrizze, hogy a feladat befejeződött-e. Ha elkészült, az eredményt a kap módszer.

2.3. CompletableFuture

Bemutatták a Java 8-at CompletableFuture a kombinációjával Jövő és CompletionStage. Különféle módszereket biztosít, mint pl supplyAsync, runAsync, és majdApplyAsync aszinkron programozáshoz.

Tehát, használjuk a CompletableFuture helyett FutureTask hogy megtalálja egy szám faktoriálját:

CompletableFuture completeableFuture = CompletableFuture.supplyAsync (() -> faktoriális (szám)); while (! completeableFuture.isDone ()) {System.out.println ("A CompletableFuture még nem fejeződött be ..."); } hosszú eredmény = completeableFuture.get ();

Nincs szükségünk a ExecutorService kifejezetten. A CompletableFuture belsőleg használja ForkJoinPool hogy a feladatot aszinkron módon kezelje. Ezért sokkal tisztábbá teszi a kódunkat.

3. Guava

Gujávafa biztosítja a Hallható jövő osztály aszinkron műveletek végrehajtására.

Először hozzáadjuk a legfrissebbet gujávafa Maven-függőség:

 com.google.guava guava 28.2-jre 

Ezután keressük meg a szám tényezőjét a Hallható jövő:

ExecutorService threadpool = Executors.newCachedThreadPool (); ListeningExecutorService service = MoreExecutors.listeningDecorator (threadpool); ListenableFuture guavaFuture = (ListenableFuture) service.submit (() -> faktoriális (szám)); hosszú eredmény = guavaFuture.get ();

Itt a Végrehajtók osztály adja meg a ListeningExecutorService osztály. Aztán a ListeningExecutorService.submit metódus aszinkron módon hajtja végre a feladatot, és visszaadja a Hallható jövő.

Guava-nak van egy Határidős osztály, amely olyan módszereket nyújt, mint submitAsync, ütemezésAszinkron, és transformAsync hogy láncolja a Hallható jövő hasonló a CompletableFuture.

Lássuk például, hogyan kell használni Futures.submitAsync helyett ListeningExecutorService.submit módszer:

ListeningExecutorService service = MoreExecutors.listeningDecorator (threadpool); AsyncCallable asyncCallable = Callables.asAsyncCallable (new Callable () {public Long call () {return factorial (number);}}, service); ListenableFuture guavaFuture = Futures.submitAsync (asyncCallable, szolgáltatás);

Itt a submitAsync metódus megköveteli az argumentumát AsyncCallable, amely a Hívhatók osztály.

Ezenkívül a Határidős osztály biztosítja a addCallback módszer a siker és a kudarc visszahívások regisztrálásához

Futures.addCallback (factorialFuture, új FutureCallback () {public void onSuccess (Long factorial) {System.out.println (factorial);} public void onFailure (Throwable dobott) {thrown.getCause ();}}, szolgáltatás);

4. EA Async

Az Electronic Arts az .yn keresztül az async-wait funkciót a .NET-től a Java ökoszisztémájába juttatta ea-aszinkron könyvtár.

A könyvtár lehetővé teszi aszinkron (nem blokkoló) kódok egymás utáni írását. Ezért megkönnyíti az aszinkron programozást és természetesen méretez.

Először hozzáadjuk a legfrissebbet ea-aszinkron Maven-függőség a pom.xml:

 com.ea.async ea-async 1.2.3 

Ezután alakítsuk át a korábban tárgyaltakat CompletableFuture kódot a várják az EA által biztosított módszer Async osztály:

statikus {Async.init (); } public long factorialUEAEAsync használata (int szám) {CompletableFuture completeableFuture = CompletableFuture.supplyAsync (() -> faktoriális (szám)); hosszú eredmény = Async.await (completeableFuture); }

Itt felhívjuk a Async.init módszer a statikus blokk a Async futásidejű műszerezés.

Async A műszer futás közben átalakítja a kódot, és átírja a várják módszerrel, hasonlóan viselkedni, mint a CompletableFuture.

Ebből kifolyólag, a hívás a várják módszer hasonló a híváshoz Jövő.csatlakozzon.

Használhatjuk a - javaagent JVM paraméter a fordítási idejű műszerezéshez. Ez egy alternatíva a Async.init módszer:

java -javaagent: ea-async-1.2.3.jar -cp 

Vizsgáljuk meg az aszinkron kód szekvenciális írásának egy másik példáját.

Először aszinkron módon hajtunk végre néhány láncműveletet az olyan kompozíciós módszerekkel, mint a majdComposeAsync és majdAcceptAsync a CompletableFuture osztály:

CompletableFuture completeableFuture = hello () .thenComposeAsync (hello -> mergeWorld (hello)) .thenAcceptAsync (helloWorld -> print (helloWorld)) .kivételesen (dobható -> {System.out.println (dobható.get null) () ;}); completeableFuture.get ();

Ezután átalakíthatjuk a kódot az EA-k segítségével Async.await ():

próbáld meg {String hello = wait (hello ()); Karakterlánc helloWorld = várja (mergeWorld (hello)); várjon (CompletableFuture.runAsync (() -> print (helloWorld))); } catch (e kivétel) {e.printStackTrace (); }

A megvalósítás hasonlít a szekvenciális blokkoló kódra. Azonban a várják metódus nem blokkolja a kódot.

Mint megbeszéltük, minden hívás a várják metódust a Async hangszerelés, hogy hasonlóan működjön Jövő.csatlakozzon módszer.

Tehát, miután az aszinkron végrehajtás Helló a módszer elkészült, a Jövő eredmény átkerül a mergeWorld módszer. Ezután az eredmény átkerül az utolsó végrehajtáshoz a CompletableFuture.runAsync módszer.

5. Kaktuszok

A Cactoos egy Java könyvtár, amely objektum-orientált elveken alapul.

A Google Guava és az Apache Commons alternatívája, amely közös objektumokat biztosít a különböző műveletek végrehajtásához.

Először tegyük hozzá a legfrissebbet kaktuszok Maven-függőség:

 org.cactoos kaktuszok 0,43 

A könyvtár biztosítja Async osztály aszinkron műveletekhez.

Tehát a Cactoos példánya segítségével megtalálhatjuk egy szám faktoriálját Async osztály:

Async asyncFunction = új Async (input -> faktoriális (input)); Jövő asyncFuture = asyncFunction.apply (szám); hosszú eredmény = asyncFuture.get ();

Itt, a alkalmaz metódus a műveletet a ExecutorService.submit metódus, és a Jövő felület.

Hasonlóképpen a Async osztály rendelkezik a exec módszer, amely ugyanazt a funkciót biztosítja visszatérési érték nélkül.

Megjegyzés: A Cactoos könyvtár a fejlesztés kezdeti szakaszában van, és lehet, hogy még nem megfelelő a gyártáshoz.

6. Jcabi-szempontok

A Jcabi-Aspects biztosítja a @Aszinkron annotáció az aszinkron programozáshoz az AspectJ AOP szempontokon keresztül.

Először tegyük hozzá a legfrissebbet jcabi-szempontok Maven-függőség:

 com.jcabi jcabi-szempontok 0.22.6 

A jcabi-szempontok könyvtár AspectJ futásidejű támogatást igényel. Tehát hozzáadjuk a aspektjrt Maven-függőség:

 org.aspectj aspektjrt 1.9.5 

Ezután hozzáadjuk a jcabi-maven-plugin plugin, amely AspectJ szempontokkal szövi a bináris fájlokat. A plugin biztosítja a ajc cél, amely minden munkát elvégez helyettünk:

 com.jcabi jcabi-maven-plugin 0.14.1 ajc org.aspectj aspektusszerszámok 1.9.1 org. 

Tehát mindannyian készen állunk az AOP szempontok használatára az aszinkron programozáshoz:

@Async @Loggable public Future factorialUsingAspect (int szám) {Future factorialFuture = CompletableFuture.completedFuture (faktoriális (szám)); return factorialFuture; }

Amikor összeállítjuk a kódot, a könyvtár AOP tanácsokat ad be a @Aszinkron annotáció az AspectJ szövésen keresztül, a. aszinkron végrehajtásához factorialUsingAspect módszer.

Tehát állítsuk össze az osztályt a Maven paranccsal:

mvn install

A kimenet a jcabi-maven-plugin kinézhet:

 --- jcabi-maven-plugin: 0.14.1: ajc (alapértelmezett) @ java-async --- [INFO] jcabi-szempontok 0.18 / 55a5c13 új démon szál jcabi-loggable programot indított a @Loggable kommentált módszerek megtekintéséhez [INFO] A nem szövött osztályokat a / tutorials / java-async / target / woven [INFO] jcabi-szempontok 0.18 / 55a5c13 új démon szál jcabi-cache-be másolják a lejárt @Cacheable értékek automatikus tisztításához [INFO] ajc eredmény: 10 fájl ) feldolgozva, 0 pontvágás szőtt, 0 hiba (ok), 0 figyelmeztetés (ek)

A naplók ellenőrzésével ellenőrizhetjük, hogy osztályunk megfelelően szőtt-e jcabi-ajc.log fájl, amelyet a Maven plugin generált:

Csatlakozási pont 'metódus-végrehajtás (java.util.concurrent.Future com.baeldung.async.JavaAsync.factorialUsingJcabiAspect (int))' a 'com.baeldung.async.JavaAsync' (JavaAsync.java:158) típusban, körültekintő tanácsokkal innen: 'com.jcabi.aspects.aj.MethodAsyncRunner' (jcabi-szempontok-0.22.6.jar! MethodAsyncRunner.class (a MethodAsyncRunner.java-ból))

Ezután futtatjuk az osztályt egyszerű Java alkalmazásként, és a kimenet a következőképpen fog kinézni:

17: 46: 58.245 [main] INFO com.jcabi.aspects.aj.NamedThreads - jcabi-szempontok 0.22.6 / 3f0a1f7 elindított egy új démon szál jcabi-naplózhatót a @Loggable annotált módszerek megtekintéséhez 17: 46: 58.355 [main] INFO com.jcabi.aspects.aj.NamedThreads - jcabi-aspektusok 0.22.6 / 3f0a1f7 új démon szál jcabi-async programot indítottak aszinkron módszer végrehajtásához 17: 46: 58.358 [jcabi-async] INFO com.baeldung.async.JavaAsync - #factorialUectJcabi (20): '[email protected] [Completed normal]' 44,64µs-ban

Tehát láthatunk egy új démon szálat jcabi-aszinkron a feladatot aszinkron módon végrehajtó könyvtár hozza létre.

Hasonlóképpen, a naplózást a @Loggable a könyvtár által biztosított feljegyzés.

7. Következtetés

Ebben a cikkben az aszinkron programozás néhány módját láthattuk a Java-ban.

Először is feltártuk a Java beépített funkcióit, mint például FutureTask és CompletableFuture aszinkron programozáshoz. Aztán láttunk néhány olyan könyvtárat, mint az EA Async és a Cactoos, dobozon kívüli megoldásokkal.

Megvizsgáltuk a feladatok aszinkron végrehajtásának támogatását is Guava segítségével Hallható jövő és Határidős osztályok. Végül feltártuk a jcabi-AspectJ könyvtárat, amely az AOP funkciókat biztosítja rajta keresztül @Aszinkron annotáció az aszinkron metódushívásokhoz.

Szokás szerint az összes kód implementáció elérhető a GitHubon.