Vodič za Java Phaser

1. Pregled

U ovom ćemo članku pogledati Phaser konstruirati iz java.util.concurrent paket. To je vrlo slična konstrukcija CountDownLatch koji nam omogućuje koordinaciju izvođenja niti. U usporedbi s CountDownLatch, ima neku dodatnu funkcionalnost.

The Phaser je prepreka na kojoj dinamički broj niti treba pričekati prije nastavka izvršavanja. U CountDownLatch taj se broj ne može dinamički konfigurirati i treba ga navesti prilikom stvaranja instance.

2. Phaser API

The Phaser omogućuje nam izgradnju logike u kojoj niti trebaju pričekati na barijeri prije nego što prijeđu na sljedeći korak izvršenja.

Možemo koordinirati više faza izvršenja, ponovnom upotrebom a Phaser primjer za svaku programsku fazu. Svaka faza može imati različit broj niti koji čekaju prelazak u drugu fazu. Kasnije ćemo pogledati primjer korištenja faza.

Da bi sudjelovala u koordinaciji, nit mora Registar() sebe s Phaser primjer. Imajte na umu da ovo samo povećava broj registriranih strana i ne možemo provjeriti je li trenutna nit registrirana - implementaciju bismo trebali podrazvrstiti da to podržava.

Konac signalizira da je na prepreku stigao pozivom na acceptAndAwaitAdvance (), što je metoda blokiranja. Kada je broj pristiglih strana jednak broju registriranih, izvođenje programa nastavit će se, a broj faze će se povećati. Broj trenutne faze možemo dobiti pozivom na getPhase () metoda.

Kad nit završi svoj posao, trebali bismo nazvati acceptAndDeregister () metoda koja signalizira da se trenutna nit više ne smije uzimati u obzir u ovoj određenoj fazi.

3. Primjena logičke upotrebe Phaser API

Recimo da želimo koordinirati više faza djelovanja. Tri niti će obraditi prvu fazu, a dvije niti drugu fazu.

Stvorit ćemo a LongRunningAction klasa koja provodi Izvodljivo sučelje:

klasa LongRunningAction implementira Runnable {private String threadName; privatni Phaser ph; LongRunningAction (String threadName, Phaser ph) {this.threadName = threadName; this.ph = ph; ph.register (); } @Override public void run () {ph.arriveAndAwaitAdvance (); isprobajte {Thread.sleep (20); } catch (InterruptedException e) {e.printStackTrace (); } ph.arriveAndDeregister (); }}

Kada se instancira naša klasa akcije, mi se registriramo na Phaser primjer pomoću Registar() metoda. To će povećati broj niti koristeći tu specifičnu Phaser.

Poziv na acceptAndAwaitAdvance () učinit će da trenutna nit čeka na pregradi. Kao što je već spomenuto, kada broj prispjelih stranaka postane jednak broju registriranih, izvršenje će se nastaviti.

Nakon završetka obrade, trenutna nit sama se odjavljuje pozivanjem datoteke acceptAndDeregister () metoda.

Stvorimo testni slučaj u kojem ćemo započeti tri LongRunningAction niti i blok na pregradi. Dalje, nakon završetka akcije stvorit ćemo dvije dodatne LongRunningAction niti koje će izvršiti obradu sljedeće faze.

Prilikom stvaranja Phaser primjer iz glavne niti, prolazimo 1 kao argument. To je ekvivalentno pozivanju Registar() metoda iz trenutne niti. To radimo jer je, kada stvaramo tri radničke niti, glavna nit koordinator, a time i Phaser treba imati registrirane četiri niti:

ExecutorService executorService = Izvršitelji.newCachedThreadPool (); Phaser ph = novi Phaser (1); assertEquals (0, ph.getPhase ());

Faza nakon inicijalizacije jednaka je nuli.

The Phaser klasa ima konstruktor u kojem joj možemo proslijediti roditeljsku instancu. Korisno je u slučajevima kada imamo velik broj stranaka koje bi doživjele velike troškove zbog usklađivanja. U takvim situacijama, slučajevi Fazeri može se postaviti tako da grupe podfazera dijele zajedničkog roditelja.

Dalje, krenimo s tri LongRunningAction niti akcije, koje će čekati na barijeri dok ne pozovemo acceptAndAwaitAdvance () metoda iz glavne niti.

Imajte na umu da smo inicijalizirali naš Phaser s 1 i nazvao Registar() još tri puta. Sada su tri akcijske niti najavile da su stigle do barijere, pa još jedan poziv acceptAndAwaitAdvance () je potreban - onaj iz glavne niti:

executorService.submit (nova LongRunningAction ("nit-1", ph)); executorService.submit (nova LongRunningAction ("nit-2", ph)); executorService.submit (nova LongRunningAction ("nit-3", ph)); ph.arriveAndAwaitAdvance (); assertEquals (1, ph.getPhase ());

Nakon završetka te faze, getPhase () metoda će vratiti jedan jer je program završio obradu prvog koraka izvršenja.

Recimo da bi dvije niti trebale provesti sljedeću fazu obrade. Možemo iskoristiti Phaser da bismo to postigli jer nam omogućuje dinamičko konfiguriranje broja niti koje bi trebale čekati na barijeri. Pokrećemo dvije nove niti, ali one se neće izvršavati sve dok poziv na acceptAndAwaitAdvance () iz glavne niti (isto kao u prethodnom slučaju):

executorService.submit (nova LongRunningAction ("nit-4", ph)); executorService.submit (nova LongRunningAction ("nit-5", ph)); ph.arriveAndAwaitAdvance (); assertEquals (2, ph.getPhase ()); ph.arriveAndDeregister ();

Nakon ovoga, getPhase () metoda će vratiti broj faze jednak dva. Kada želimo završiti naš program, moramo nazvati acceptAndDeregister () metoda kao glavna nit još uvijek je registrirana u Phaser. Kad odjava uzrokuje da broj registriranih strana postane nula, Phaser je raskinuta. Svi pozivi metodama sinkronizacije više se neće blokirati i odmah će se vratiti.

Pokretanje programa će proizvesti sljedeći izlaz (puni izvorni kod s ispisima redaka za ispis može se naći u spremištu koda):

Ovo je faza 0 Ovo je faza 0 Ovo je faza 0 Navoj navoja-2 prije dugotrajnog djelovanja Navoj navoja-1 prije dugotrajnog djelovanja Navoj navoja-3 prije dugotrajnog djelovanja Ovo je faza 1 Ovo je faza 1 Navoj navoja-4 prije dugog pokrenuta akcija Navoj niti-5 prije dugotrajnog izvođenja

Vidimo da sve niti čekaju izvršenje dok se prepreka ne otvori. Sljedeća faza izvršenja izvodi se tek kada je prethodna uspješno završila.

4. Zaključak

U ovom vodiču pogledali smo Phaser konstruirati od java.util.concurrent i implementirali smo koordinacijsku logiku u više faza koristeći Phaser razred.

Provedbu svih ovih primjera i isječaka koda možete pronaći u projektu GitHub - ovo je Maven projekt, pa bi ga trebalo lako uvesti i pokrenuti kakav jest.


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