Asynkron programmering i Java

1. Oversikt

Med den økende etterspørselen etter å skrive ikke-blokkerende kode, trenger vi måter å utføre koden asynkront.

I denne opplæringen vil vi se på noen måter å oppnå asynkron programmering i Java. Vi vil også utforske noen få Java-biblioteker som tilbyr direkte tilgjengelige løsninger.

2. Asynkron programmering i Java

2.1. Tråd

Vi kan opprette en ny tråd for å utføre enhver operasjon asynkront. Med lanseringen av lambdauttrykk i Java 8 er det renere og mer lesbart.

La oss lage en ny tråd som beregner og skriver ut et talls faktor:

int tall = 20; Tråd newThread = ny tråd (() -> {System.out.println ("Faktor av" + nummer + "er:" + faktor (nummer));}); newThread.start ();

2.2. FutureTask

Siden Java 5, Framtid grensesnittet gir en måte å utføre asynkrone operasjoner på FutureTask.

Vi kan bruke sende inn metoden for ExecutorService for å utføre oppgaven asynkront og returnere forekomsten av FutureTask.

Så, la oss finne et tall:

ExecutorService threadpool = Executors.newCachedThreadPool (); Future futureTask = threadpool.submit (() -> factorial (number)); while (! futureTask.isDone ()) {System.out.println ("FutureTask er ikke ferdig ennå ..."); } langt resultat = futureTask.get (); threadpool.shutdown ();

Her har vi brukt er ferdig metoden som tilbys av Framtid grensesnitt for å sjekke om oppgaven er fullført. Når du er ferdig, kan vi hente resultatet ved hjelp av metode.

2.3. Fullførbar fremtid

Java 8 introdusert Fullførbar fremtid med en kombinasjon av en Framtid og CompletionStage. Det gir forskjellige metoder som supplyAsync, runAsync, og thenApplyAsync for asynkron programmering.

Så la oss bruke Fullførbar fremtid i stedet for FutureTask for å finne et tallfaktor:

CompletableFuture completeableFuture = CompletableFuture.supplyAsync (() -> faktor (nummer)); while (! completeableFuture.isDone ()) {System.out.println ("CompletableFuture er ikke ferdig ennå ..."); } langt resultat = completeFuture.get ();

Vi trenger ikke bruke ExecutorService eksplisitt. De Fullførbar fremtid internt bruk ForkJoinPool for å håndtere oppgaven asynkront. Derfor gjør det koden vår mye renere.

3. Guava

Guava gir den ListenableFuture klasse for å utføre asynkrone operasjoner.

Først vil vi legge til det siste guava Maven avhengighet:

 com.google.guava guava 28.2-jre 

La oss så finne et tall som bruker fakturaen ListenableFuture:

ExecutorService threadpool = Executors.newCachedThreadPool (); ListeningExecutorService service = MoreExecutors.listeningDecorator (threadpool); ListenableFuture guavaFuture = (ListenableFuture) service.submit (() -> factorial (number)); langt resultat = guavaFuture.get ();

Her, den MoreExecutors klasse gir forekomsten av ListeningExecutorService klasse. Og så ListeningExecutorService.submit metoden utfører oppgaven asynkront og returnerer forekomsten av ListenableFuture.

Guava har også en Fremtid klasse som gir metoder som submitAsync, planAsync, og transformAsync å kjede ListenableFutures ligner på Fullførbar fremtid

La oss for eksempel se hvordan du bruker Futures.submitAsync i stedet for ListeningExecutorService.submit metode:

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

Her, den submitAsync metoden krever et argument av AsyncCallable, som er opprettet ved hjelp av Callables klasse.

I tillegg har Fremtid klasse gir addCallback metode for å registrere suksess og fiasko tilbakeringinger:

Futures.addCallback (factorialFuture, ny FutureCallback () {public void onSuccess (Long factorial) {System.out.println (factorial);} public void onFailure (Throwable throw) {throw.getCause ();}}, service);

4. EA Async

Electronic Arts brakte den asynk-ventende funksjonen fra .NET til Java-økosystemet gjennom ea-async bibliotek.

Biblioteket tillater å skrive asynkron (ikke-blokkerende) kode sekvensielt. Derfor gjør det asynkron programmering enklere og skaleres naturlig.

Først legger vi til det siste ea-async Maven avhengighet til pom.xml:

 com.ea.async ea-async 1.2.3 

La oss så transformere det tidligere diskuterte Fullførbar fremtid ved å bruke avvente metoden levert av EAs Asynkronisering klasse:

statisk {Async.init (); } public long factorialUsingEAAsync (int number) {CompletableFuture completeableFuture = CompletableFuture.supplyAsync (() -> factorial (number)); langt resultat = Async.await (completeFuture); }

Her ringer vi til Async.init metoden i statisk blokker for å initialisere Asynkronisering kjøretidsinstrumentering.

Asynkronisering instrumentering forvandler koden ved kjøretid og skriver om samtalen til avvente metode, for å oppføre seg på samme måte som å bruke kjeden til Fullførbar fremtid.

Derfor, samtalen til avvente metoden ligner på å ringe Future. Bli med.

Vi kan bruke - javaagent JVM-parameter for kompileringstidsinstrumentering. Dette er et alternativ til Async.init metode:

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

La oss undersøke et annet eksempel på å skrive asynkron kode sekvensielt.

Først skal vi utføre noen kjedeoperasjoner asynkront ved å bruke sammensetningsmetodene som deretterComposeAsync og thenAcceptAsync av Fullførbar fremtid klasse:

CompletableFuture completeableFuture = hallo () .thenComposeAsync (hallo -> mergeWorld (hei)) .thenAcceptAsync (helloWorld -> print (helloWorld)). Unntaksvis (kastbar -> {System.out.println (throwable.getCause ()); return null ;}); completeableFuture.get ();

Deretter kan vi transformere koden ved hjelp av EA-er Async.await ():

prøv {String hei = vent (hallo ()); String helloWorld = avvente (mergeWorld (hallo)); avvente (CompletableFuture.runAsync (() -> print (helloWorld))); } fange (Unntak e) {e.printStackTrace (); }

Implementeringen ligner den sekvensielle blokkeringskoden. Imidlertid, den avvente metoden blokkerer ikke koden.

Som diskutert, samtaler til avvente metoden vil bli omskrevet av Asynkronisering instrumentering for å fungere på samme måte som Future. Bli med metode.

Så når den asynkrone kjøringen av Hallo metoden er ferdig, Framtid resultatet blir sendt til mergeWorld metode. Deretter blir resultatet sendt til den siste kjøringen ved hjelp av CompletableFuture.runAsync metode.

5. Kaktoer

Cactoos er et Java-bibliotek basert på objektorienterte prinsipper.

Det er et alternativ til Google Guava og Apache Commons som gir vanlige objekter for å utføre forskjellige operasjoner.

La oss først legge til det siste kaktoer Maven avhengighet:

 org.cactoos kaktoer 0.43 

Biblioteket tilbyr en Asynkronisering klasse for asynkrone operasjoner.

Så, vi kan finne et talls faktor ved å bruke forekomsten av Cactoos Asynkronisering klasse:

Async asyncFunction = new Async (input -> factorial (input)); Fremtidig asyncFuture = asyncFunction.apply (nummer); langt resultat = asyncFuture.get ();

Her, de søke om metoden utfører operasjonen ved hjelp av ExecutorService.send metode og returnerer en forekomst av Framtid grensesnitt.

Tilsvarende Asynkronisering klassen har utføre metode som gir den samme funksjonen uten returverdi.

Merk: Cactoos-biblioteket er i de innledende stadiene av utviklingen og er kanskje ikke passende for produksjonsbruk ennå.

6. Jcabi-aspekter

Jcabi-Aspects tilbyr @Async kommentar for asynkron programmering gjennom AspectJ AOP-aspekter.

La oss først legge til det siste jcabi-aspekter Maven avhengighet:

 com.jcabi jcabi-aspekter 0.22.6 

De jcabi-aspekter biblioteket krever AspectJ kjøretidsstøtte. Så, vi legger til aspectjrt Maven avhengighet:

 org.aspectj aspectjrt 1.9.5 

Deretter legger vi til jcabi-maven-plugin plugin som vever binærfiler med AspectJ-aspekter. Plugin gir ajc mål som gjør alt arbeidet for oss:

 com.jcabi jcabi-maven-plugin 0.14.1 ajc org.aspectj aspectjtools 1.9.1 org.aspectj aspectjweaver 1.9.1 

Så vi er klare til å bruke AOP-aspektene til asynkron programmering:

@Async @Loggable public Future factorialUsingAspect (int number) {Future factorialFuture = CompletableFuture.completedFuture (factorial (number)); return factorialFuture; }

Når vi kompilerer koden, biblioteket vil injisere AOP-råd i stedet for @Async kommentar gjennom AspectJ-veving, for asynkron kjøring av factorialUsingAspect metode.

Så la oss kompilere klassen ved hjelp av Maven-kommandoen:

mvn installere

Resultatet fra jcabi-maven-plugin kan se ut som:

 --- jcabi-maven-plugin: 0.14.1: ajc (standard) @ java-async --- [INFO] jcabi-aspect 0.18 / 55a5c13 startet ny daemon-tråd jcabi-loggable for å se på @Loggable kommenterte metoder [INFO] Ikke-vevde klasser blir kopiert til / tutorials / java-async / target / unwoven [INFO] jcabi-aspect 0.18 / 55a5c13 startet ny daemon-tråd jcabi-cacheable for automatisk rengjøring av utløpte @Cacheable-verdier [INFO] ajc resultat: 10 fil (er ) behandlet, 0 pekesnitt (er) vevd, 0 feil (er), 0 advarsel (er)

Vi kan kontrollere om klassen vår er vevd riktig ved å sjekke loggene i jcabi-ajc.log fil, generert av Maven-plugin:

Bli med på punkt 'metodeutførelse (java.util.concurrent.Future com.baeldung.async.JavaAsync.factorialUsingJcabiAspect (int))' i Type 'com.baeldung.async.JavaAsync' (JavaAsync.java:158) anbefalt av rundt råd fra 'com.jcabi.aspects.aj.MethodAsyncRunner' (jcabi-aspect-0.22.6.jar! MethodAsyncRunner.class (fra MethodAsyncRunner.java))

Deretter kjører vi klassen som et enkelt Java-program, og utgangen vil se ut:

17: 46: 58.245 [main] INFO com.jcabi.aspects.aj.NamedThreads - jcabi-aspect 0.22.6 / 3f0a1f7 startet ny daemon thread jcabi-loggable for å se på @Loggable kommenterte metoder 17: 46: 58.355 [main] INFO com.jcabi.aspects.aj.NamedThreads - jcabi-aspect 0.22.6 / 3f0a1f7 startet ny daemon thread jcabi-async for asynkron metodeutførelse 17: 46: 58.358 [jcabi-async] INFO com.baeldung.async.JavaAsync - #factorialUsingJc (20): '[e-postbeskyttet] [Fullført normalt]' på 44,64 µs

Så vi kan se en ny daemon-tråd jcabi-async er opprettet av biblioteket som utførte oppgaven asynkront.

Tilsvarende er loggingen aktivert av @Loggable kommentar levert av biblioteket.

7. Konklusjon

I denne artikkelen har vi sett noen måter for asynkron programmering i Java.

Til å begynne med utforsket vi Java's innebygde funksjoner som FutureTask og Fullførbar fremtid for asynkron programmering. Så har vi sett noen få biblioteker som EA Async og Cactoos med out-of-the-box-løsninger.

Vi undersøkte også støtten til å utføre oppgaver asynkront ved hjelp av Guava ListenableFuture og Fremtid klasser. Sist, vi utforsket jcabi-AspectJ-biblioteket som gir AOP-funksjoner gjennom @Async kommentar for asynkrone metodesamtaler.

Som vanlig er alle kodeimplementeringene tilgjengelige på GitHub.


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