Asinkrono programiranje u Javi

1. Pregled

S rastućom potražnjom za pisanjem neblokirajućeg koda, trebaju nam načini za izvršavanje asinkronog koda.

U ovom ćemo uputstvu pogledati nekoliko načina za postizanje asinkronog programiranja u Javi. Također ćemo istražiti nekoliko Java knjižnica koje nude gotova rješenja.

2. Asinkrono programiranje u Javi

2.1. Nit

Možemo stvoriti novu nit da bismo bilo koju operaciju izvršili asinkrono. Objavljivanjem lambda izraza u Javi 8, čišći je i čitljiviji.

Stvorimo novu nit koja izračunava i ispisuje faktorijel broja:

int broj = 20; Tema newThread = nova nit (() -> {System.out.println ("Faktorijal od" + broj + "je:" + faktor (broj));}); newThread.start ();

2.2. FutureTask

Od Jave 5, Budućnost sučelje pruža način izvođenja asinkronih operacija pomoću FutureTask.

Možemo koristiti podnijeti metoda ExecutorService za izvršavanje zadatka asinkrono i vraćanje instance FutureTask.

Pa, pronađimo faktorijel broja:

ExecutorService threadpool = Izvršitelji.newCachedThreadPool (); Budućnost futureTask = threadpool.submit (() -> faktorijel (broj)); while (! futureTask.isDone ()) {System.out.println ("FutureTask još nije gotov ..."); } dugi rezultat = futureTask.get (); threadpool.shutdown ();

Evo, koristili smo Gotovo je metoda koju pruža Budućnost sučelje za provjeru je li zadatak dovršen. Kad završimo, rezultat možemo dohvatiti pomoću dobiti metoda.

2.3. CompletableFuture

Uvedena Java 8 CompletableFuture s kombinacijom a Budućnost i CompletionStage. Pruža razne metode poput supplyAsync, runAsync, i thenApplyAsync za asinkrono programiranje.

Pa, iskoristimo CompletableFuture umjesto FutureTask pronaći faktorijel broja:

CompletableFuture completableFuture = CompletableFuture.supplyAsync (() -> faktorijel (broj)); while (! completableFuture.isDone ()) {System.out.println ("CompletableFuture još nije gotov ..."); } dugi rezultat = completableFuture.get ();

Ne trebamo koristiti ExecutorService eksplicitno. The CompletableFuture interno koristi ForkJoinPool za asinhrono rješavanje zadatka. Stoga naš kod čini puno čišćim.

3. Guava

Guava pruža Slušljivo u budućnosti klase za izvođenje asinkronih operacija.

Prvo ćemo dodati najnovije guava Ovisnost o Mavenu:

 com.google.guava guava 28,2-jre 

Zatim, pronađimo faktorijel broja koristeći Slušljivo u budućnosti:

ExecutorService threadpool = Izvršitelji.newCachedThreadPool (); ListeningExecutorService service = MoreExecutors.listeningDecorator (threadpool); ListenableFuture guavaFuture = (ListenableFuture) service.submit (() -> factorial (broj)); dugi rezultat = guavaFuture.get ();

Evo, VišeIzvršitelji klasa pruža instancu ListeningExecutorService razred. Onda ListeningExecutorService.submit metoda izvršava zadatak asinkrono i vraća instancu Slušljivo u budućnosti.

Guava također ima a Budućnosti klasa koja pruža metode poput submitAsync, rasporedAsync, i transformAsync lancati Slušajuće Budućnosti slično kao CompletableFuture.

Na primjer, pogledajmo kako koristiti Futures.submitAsync umjesto ListeningExecutorService.submit metoda:

ListeningExecutorService service = MoreExecutors.listeningDecorator (threadpool); AsyncCallable asyncCallable = Callables.asAsyncCallable (novi Callable () {javni dugi poziv () {vratiti faktorijel (broj);}}, usluga); ListenableFuture guavaFuture = Futures.submitAsync (asyncCallable, usluga);

Evo, submitAsync metoda zahtijeva argument od AsyncCallable, koji se kreira pomoću Pozivi razred.

Uz to, Budućnosti razred pruža addCallback metoda za registraciju povratnih poziva za uspjeh i neuspjeh:

Futures.addCallback (factorialFuture, novi FutureCallback () {javna praznina onSuccess (Duga faktorijel) {System.out.println (factorial);} javna praznina onFailure (bacanje bačeno) {thrown.getCause ();}}, usluga);

4. EA Async

Electronic Arts donio je značajku async-await iz .NET-a u ekosustav Java putem ea-async knjižnica.

Biblioteka omogućuje sekvencijalno pisanje asinkronog (neblokirajućeg) koda. Stoga olakšava asinkrono programiranje i prirodno se skalira.

Prvo ćemo dodati najnovije ea-async Mavenova ovisnost o pom.xml:

 com.ea.async ea-async 1.2.3 

Zatim, transformirajmo prethodno raspravljeno CompletableFuture kod pomoću čekati metoda koju pružaju EA-i Async razred:

static {Async.init (); } public long factorialUsingEAAsync (int number) {CompletableFuture completableFuture = CompletableFuture.supplyAsync (() -> factorial (broj)); dugi rezultat = Async.await (completableFuture); }

Evo, pozivamo Async.init metoda u statički blok za inicijalizaciju Async runtime instrumentacija.

Async instrumentacija pretvara kôd u vrijeme izvođenja i prepisuje poziv na čekati metoda, da se ponaša slično korištenju lanca CompletableFuture.

Stoga, poziv na čekati metoda slična je pozivanju Budućnost.druži se.

Možemo koristiti - javaagent JVM parametar za instrumentaciju vremena kompajliranja. Ovo je alternativa Async.init metoda:

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

Ispitajmo još jedan primjer uzastopnog pisanja asinkronog koda.

Prvo ćemo izvesti nekoliko lančanih operacija asinkrono koristeći metode sastava poput thenComposeAsync i thenAcceptAsync od CompletableFuture razred:

CompletableFuture completableFuture = hello (). ThenComposeAsync (hello -> mergeWorld (hello)). ThenAcceptAsync (helloWorld -> print (helloWorld)) .iznimno (bacanje -> {System.out.println (throwable.getCause ()); vrati nulu ;}); completableFuture.get ();

Tada možemo transformirati kod pomoću EA-a Async.await ():

probajte {String hello = await (hello ()); Niz helloWorld = await (mergeWorld (hello)); await (CompletableFuture.runAsync (() -> ispis (helloWorld))); } catch (Iznimka e) {e.printStackTrace (); }

Implementacija sliči kodu sekvencijalnog blokiranja. Međutim čekati metoda ne blokira kôd.

Kao što je već rečeno, svi pozivi na čekati metodu će prepisati Async instrumentacija radi slično kao Budućnost.druži se metoda.

Dakle, jednom asinkrono izvršavanje zdravo metoda je gotova, Budućnost rezultat se prosljeđuje spajanjeSvijeta metoda. Zatim se rezultat prosljeđuje zadnjem izvršenju pomoću CompletableFuture.runAsync metoda.

5. Kaktusi

Cactoos je Java knjižnica koja se temelji na objektno orijentiranim načelima.

To je alternativa Google Guava i Apache Commons koja pruža zajedničke objekte za izvođenje različitih operacija.

Prvo, dodajmo najnovije kaktusi Ovisnost o Mavenu:

 org.cactoos kaktusi 0.43 

Knjižnica nudi Async klasa za asinkrone operacije.

Dakle, faktorijel broja možemo pronaći pomoću primjera Cactoosa Async razred:

Async asyncFunction = nova Async (ulaz -> faktorijel (ulaz)); Buduća asyncFuture = asyncFunction.apply (broj); dugi rezultat = asyncFuture.get ();

Ovdje, the primijeniti metoda izvršava operaciju pomoću ExecutorService.submit metoda i vraća instancu Budućnost sučelje.

Slično tome, Async razred ima izvršiti metoda koja pruža istu značajku bez povratne vrijednosti.

Napomena: Cactoosova knjižnica je u početnoj fazi razvoja i možda još nije prikladna za produkcijsku upotrebu.

6. Jcabi-aspekti

Jcabi-Aspects pruža @Async napomena za asinkrono programiranje kroz aspekte AspectJ AOP.

Prvo, dodajmo najnovije jcabi-aspekti Ovisnost o Mavenu:

 com.jcabi jcabi-aspekti 0.22.6 

The jcabi-aspekti knjižnica zahtijeva podršku za vrijeme izvođenja AspectJ. Pa ćemo dodati aspektjrt Ovisnost o Mavenu:

 org.aspectj aspektrt 1.9.5 

Dalje ćemo dodati jcabi-maven-plugin dodatak koji plete binarne datoteke s aspektima AspectJ. Dodatak pruža ajc cilj koji za nas obavlja sav posao:

 com.jcabi jcabi-maven-plugin 0.14.1 ajc org.aspectj аспектjtools 1.9.1 org.aspectj аспектjweaver 1.9.1 

Dakle, svi smo spremni koristiti AOP aspekte za asinkrono programiranje:

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

Kada kompajliramo kod, knjižnica će ubrizgati savjet o AOP-u umjesto @Async anotacija kroz AspectJ tkanje, za asinkrono izvršavanje factorialUsingAspect metoda.

Pa, kompajlirajmo klasu pomoću naredbe Maven:

mvn instalirati

Izlaz iz jcabi-maven-plugin može izgledati kao:

 --- jcabi-maven-plugin: 0.14.1: ajc (zadano) @ java-async --- [INFO] jcabi-aspekti 0.18 / 55a5c13 pokrenuo je novu demonu nit jcabi-loggable za gledanje @Loggable anotiranih metoda [INFO] Netkani razredi kopirat će se u / tutorials / java-async / target / unwoven [INFO] jcabi-аспекти 0,18 / 55a5c13 započeli su novu demon demon jcabi-cacheable za automatsko čišćenje isteklih vrijednosti @Cacheable [INFO] ajc rezultat: 10 datoteka (s) ) obrađeno, 0 utkanih tačaka, 0 pogrešaka, 0 upozorenja

Možemo provjeriti je li naša klasa pravilno tkana provjerom dnevnika u jcabi-ajc.log datoteka koju generira dodatak Maven:

Točka pridruživanja 'izvršenje metode (java.util.concurrent.Future com.baeldung.async.JavaAsync.factorialUsingJcabiAspect (int))' u Tipu 'com.baeldung.async.JavaAsync' (JavaAsync.java:158) savjetuje se oko savjeta iz 'com.jcabi.aspects.aj.MethodAsyncRunner' (jcabi-аспекти-0.22.6.jar! MethodAsyncRunner.class (iz MethodAsyncRunner.java))

Zatim ćemo pokrenuti klasu kao jednostavnu Java aplikaciju, a izlaz će izgledati ovako:

17: 46: 58.245 [glavna] INFO com.jcabi.aspects.aj.NamedThreads - jcabi-aspekti 0.22.6 / 3f0a1f7 pokrenuli su novu demonu nit jcabi-loggable za gledanje @Loggable anotiranih metoda 17: 46: 58.355 [glavna] INFO com.jcabi.aspects.aj.NamedThreads - jcabi-aspekti 0.22.6 / 3f0a1f7 pokrenuo je novu demonu nit jcabi-async za izvršavanje asinkrone metode 17: 46: 58.358 [jcabi-async] INFO com.baeldung.async.JavaAActAsssing - #factorialUctic - #factorialUctic (20): '[e-pošta zaštićena] [Dovršeno normalno]' za 44,64µs

Dakle, možemo vidjeti novu nit demona jcabi-async kreira knjižnica koja je zadatak izvršila asinkrono.

Slično tome, bilježenje omogućuje @Prijava napomena koju pruža knjižnica.

7. Zaključak

U ovom smo članku vidjeli nekoliko načina asinkronog programiranja u Javi.

Za početak smo istražili ugrađene Javine značajke poput FutureTask i CompletableFuture za asinkrono programiranje. Zatim smo vidjeli nekoliko knjižnica poput EA Async i Cactoos s gotovim rješenjima.

Također, ispitali smo podršku asinhronog izvršavanja zadataka koristeći Guava's Slušljivo u budućnosti i Budućnosti razreda. Na kraju, istražili smo jcabi-AspectJ biblioteku koja pruža AOP značajke putem svoje @Async napomena za pozive asinkrone metode.

Kao i obično, sve implementacije koda dostupne su na GitHubu.