Útmutató a Java Phaserhez

1. Áttekintés

Ebben a cikkben megnézzük a Phaser konstruálni a java.util.egyidejű csomag. Nagyon hasonló konstrukció a CountDownLatch ez lehetővé teszi számunkra a szálak végrehajtásának összehangolását. Összehasonlítva a CountDownLatch, van néhány további funkciója.

A Phaser olyan akadály, amelyen a szálak dinamikus számának meg kell várnia a végrehajtás folytatása előtt. Ban,-ben CountDownLatch ezt a számot nem lehet dinamikusan konfigurálni, és a példány létrehozásakor meg kell adni.

2. Phaser API

A Phaser lehetővé teszi számunkra a logika felépítését, amelyben a szálaknak meg kell várniuk a sorompót, mielőtt a végrehajtás következő lépésére lépnének.

A végrehajtás több szakaszát koordinálhatjuk, a Phaser az egyes programfázisokhoz. Minden fázisnak különböző számú szála lehet, amelyek egy másik fázisra való továbblépésre várnak. A későbbiekben megnézzük a fázisok használatának példáját.

A koordinációban való részvételhez a szálnak meg kell Regisztráció() magát a Phaser példa. Vegye figyelembe, hogy ez csak növeli a regisztrált felek számát, és nem tudjuk ellenőrizni, hogy az aktuális szál regisztrálva van-e - a támogatást alosztályba kell sorolnunk.

A szál jelzi, hogy a sorompóhoz úgy érkezett, hogy felhívta a érkezikAndAwaitAdvance (), amely blokkolási módszer. Amikor az érkező felek száma megegyezik a regisztráltak számával, a program végrehajtása folytatódik, és a fázisszám növekszik. Az aktuális fázisszámot a getPhase () módszer.

Amikor a szál befejezi a munkáját, meg kell hívnunk a érkezik és regisztráljon () módszer annak jelzésére, hogy az adott szálat ebben a fázisban már nem kell elszámolni.

3. A logika használata Phaser API

Tegyük fel, hogy a cselekvések több szakaszát szeretnénk összehangolni. Három szál fogja feldolgozni az első fázist, két szál pedig a második fázist.

Létrehozunk egy LongRunningAction osztály, amely végrehajtja a Futható felület:

class LongRunningAction megvalósítja a Runnable {private String threadName; magán Phaser ph; LongRunningAction (String szálnév, Phaser ph) {this.szálnév = szálnév; ez.ph = ph; ph.register (); } @Orride public void run () {ph.arriveAndAwaitAdvance (); próbáld ki a {Thread.sleep (20); } catch (InterruptedException e) {e.printStackTrace (); } ph.arriveAndDeregister (); }}

Amikor az akcióosztályunkat példányosítjuk, regisztrálunk a Phaser például a Regisztráció() módszer. Ez növeli az adott szálat használó szálak számát Phaser.

A hívás a érkezikAndAwaitAdvance () az aktuális szál várakozik a sorompón. Mint már említettük, amikor az érkező felek száma megegyezik a regisztráltak számával, a végrehajtás folytatódik.

A feldolgozás befejezése után az aktuális szál törli a regisztrációját a érkezik és regisztráljon () módszer.

Készítsünk egy tesztesetet, amelyben hármat kezdünk LongRunningAction szálak és tömb a sorompón. Ezután, miután a művelet befejeződött, létrehozunk további két elemet LongRunningAction szálak, amelyek végrehajtják a következő fázis feldolgozását.

Létrehozáskor Phaser például a fő szálból, elhaladunk 1 érvként. Ez egyenértékű a Regisztráció() metódus az aktuális szálból. Ezt azért tesszük, mert amikor három munkásszálat hozunk létre, a fő szál egy koordinátor, ezért a Phaser négy szálat kell regisztrálni hozzá:

ExecutorService végrehajtóService = Executors.newCachedThreadPool (); Phaser ph = új Phaser (1); assertEquals (0, ph.getPhase ());

Az inicializálás utáni szakasz nulla.

A Phaser osztályban van egy konstruktor, amelyben átadhatunk neki egy szülőpéldányt. Hasznos azokban az esetekben, amikor nagyszámú pártunk van, amelyek hatalmas szinkronizációs versenyköltségekkel járnának. Ilyen helyzetekben előfordulhatnak Phaserek felállítható úgy, hogy az alfázisok csoportjai közös szülővel rendelkezzenek.

Ezután kezdjük el a hármat LongRunningAction akciószálak, amelyek addig várnak a sorompón, amíg meg nem hívjuk a érkezikAndAwaitAdvance () módszer a fő szálból.

Ne feledje, hogy inicializáltuk Phaser val vel 1 és felhívta Regisztráció() még háromszor. Három akciószál jelentette be, hogy megérkeztek a sorompóhoz, tehát még egy felhívás érkezikAndAwaitAdvance () szükséges - a fő szálból:

executorService.submit (új LongRunningAction ("thread-1", ph)); executorService.submit (új LongRunningAction ("thread-2", ph)); executorService.submit (új LongRunningAction ("thread-3", ph)); ph.arriveAndAwaitAdvance (); assertEquals (1, ph.getPhase ());

A fázis befejezése után a getPhase () metódus visszatér, mert a program befejezte a végrehajtás első lépésének feldolgozását.

Tegyük fel, hogy két szálnak kell elvégeznie a feldolgozás következő szakaszát. Kihasználhatjuk Phaser ennek elérése, mert ez lehetővé teszi számunkra a szálak számának dinamikus konfigurálását, amelyeknek várniuk kell a sorompóra. Két új szálat indítunk, de ezek végrehajtása csak a érkezikAndAwaitAdvance () a fő szálból (ugyanaz, mint az előző esetben):

executorService.submit (új LongRunningAction ("thread-4", ph)); executorService.submit (új LongRunningAction ("thread-5", ph)); ph.arriveAndAwaitAdvance (); assertEquals (2, ph.getPhase ()); ph.arriveAndDeregister ();

Ezek után a getPhase () metódus kettővel egyenlő fázisszámot ad vissza. Amikor be akarjuk fejezni a programunkat, felhívnunk kell a érkezik és regisztráljon () metódus, mivel a fő szál még mindig regisztrálva van a Phaser. Ha a regisztráció törlése miatt a regisztrált felek száma nulla lesz, a Phaser van megszűnt. A szinkronizálási módszerek összes hívása már nem blokkolódik, és azonnal visszatér.

A program futtatása a következő kimenetet hozza létre (a teljes forráskód a nyomtatási sor utasításokkal megtalálható a kódtárban):

Ez a 0 fázis Ez a 0 fázis Ez a 0 fázis A 2. menet szála hosszú futási művelet előtt 1. szál szál hosszú futási művelet előtt A 3. szál szál hosszú futási művelet előtt Ez az 1. fázis Ez az 1. fázis A 4. szál szála hosszú futóművelet Az 5-ös szálat futtassa hosszú futás előtt

Látjuk, hogy az összes szál végrehajtásra vár, amíg a sorompó ki nem nyílik. A végrehajtás következő szakaszát csak akkor hajtjuk végre, amikor az előző sikeresen befejeződött.

4. Következtetés

Ebben az oktatóanyagban megnéztük a Phaser konstruálni java.util.egyidejű és a koordinációs logikát több fázissal valósítottuk meg a Phaser osztály.

Ezeknek a példáknak és kódrészleteknek a megvalósítása megtalálható a GitHub projektben - ez egy Maven projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.


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