Uvod u Exchanger na Javi

1. Pregled

U ovom uputstvu ćemo pogledati java.util.concurrent.Exchanger. To djeluje kao zajednička točka za razmjenu objekata između dviju niti u Javi.

2. Uvod u Exchanger

The Izmjenjivač klasa u Javi može se koristiti za dijeljenje objekata između dvije niti tipa T. Klasa pruža samo jednu preopterećenu metodu razmjena (T t).

Kad se pozove razmjena čeka da je pozove i druga nit u paru. U ovom trenutku druga nit pronalazi da prva nit čeka sa svojim objektom. Nit razmjenjuje predmete koje drže i signalizira razmjenu i sada se mogu vratiti.

Pogledajmo primjer kako bismo razumjeli razmjenu poruka između dviju niti s Izmjenjivač:

@Test javna praznina givenThreads_whenMessageExchanged_thenCorrect () {Izmjenjivač izmjenjivača = novi izmjenjivač (); Izvršni zadatakA = () -> {try {String message = razmjenjivač.exchange ("od A"); assertEquals ("od B", poruka); } catch (InterruptedException e) {Thread.currentThread.interrupt (); baciti novi RuntimeException (e); }}; Izvršni zadatakB = () -> {try {String message = razmjenjivač.exchange ("od B"); assertEquals ("iz A", poruka); } catch (InterruptedException e) {Thread.currentThread.interrupt (); baciti novi RuntimeException (e); }}; CompletableFuture.allOf (runAsync (taskA), runAsync (taskB)). Join (); }

Ovdje imamo dvije niti koje međusobno razmjenjuju poruke koristeći zajednički izmjenjivač. Pogledajmo primjer gdje zamjenjujemo objekt iz glavne niti s novom niti:

@Test javna praznina givenThread_WhenExchangedMessage_thenCorrect () baca InterruptedException {izmjenjivač izmjenjivača = novi izmjenjivač (); Izvodljivi trkač = () -> {try {String message = exchangeer.exchange ("from runner"); assertEquals ("trkaču", poruka); } catch (InterruptedException e) {Thread.currentThread.interrupt (); baciti novi RuntimeException (e); }}; Rezultat CompletableFuture = CompletableFuture.runAsync (trkač); Niz msg = exchangeer.exchange ("trkaču"); assertEquals ("od trkača", msg); rezultat.join (); }

Imajte na umu da moramo pokrenuti trkač nit prvo i kasnije poziv razmjena () u glavnoj niti.

Također imajte na umu da poziv prve niti može isteći ako druga nit ne dosegne točku razmjene na vrijeme. Koliko dugo prva nit treba čekati, može se kontrolirati pomoću preopterećenog razmjena (T t, dugo vrijeme čekanja, TimeUnit timeUnit).

3. Nema razmjene podataka GC-a

Izmjenjivač može se koristiti za stvaranje uzoraka cjevovoda s prosljeđivanjem podataka iz jedne niti u drugu. U ovom ćemo odjeljku stvoriti jednostavni snop niti koji neprekidno prenose podatke međusobno kao cjevovod.

@Test javna praznina givenData_whenPassedThrough_thenCorrect () baca InterruptedException {Exchanger readerExchanger = novi Exchanger (); Izmjenjivač writerExchanger = novi Exchanger (); Čitač koji se može izvoditi = () -> {Red za čitanjeBuffer = novi ConcurrentLinkedQueue (); while (true) {readerBuffer.add (UUID.randomUUID (). toString ()); if (readerBuffer.size ()> = BUFFER_SIZE) {readerBuffer = readerExchanger.exchange (readerBuffer); }}}; Izvodljivi procesor = () -> {Red čekanja ProcessBuffer = novi ConcurrentLinkedQueue (); Red piscaBuffer = novi ConcurrentLinkedQueue (); processorBuffer = readerExchanger.exchange (processorBuffer); while (true) {writerBuffer.add (processorBuffer.poll ()); if (processorBuffer.isEmpty ()) {processorBuffer = readerExchanger.exchange (processorBuffer); writerBuffer = writerExchanger.exchange (writerBuffer); }}}; Izvodljivi pisač = () -> {Red piscaBuffer = novi ConcurrentLinkedQueue (); writerBuffer = writerExchanger.exchange (writerBuffer); while (true) {System.out.println (writerBuffer.poll ()); if (writerBuffer.isEmpty ()) {writerBuffer = writerExchanger.exchange (writerBuffer); }}}; CompletableFuture.allOf (runAsync (čitač), runAsync (procesor), runAsync (pisač)). Join (); }

Ovdje imamo tri niti: čitač, procesor, i pisac. Zajedno rade kao jedan cjevovod i međusobno razmjenjuju podatke.

The čitačExchange dijeli se između čitač i procesor nit, dok je pisacExchanger dijeli se između procesor i pisac nit.

Primijetite da je ovdje primjer samo za demonstraciju. Moramo biti oprezni dok stvaramo beskonačne petlje s dok (istina). Da bi kôd bio čitljiv, izostavili smo rukovanje nekim iznimkama.

Ovaj obrazac razmjene podataka tijekom ponovne upotrebe međuspremnika omogućuje manje sakupljanja smeća. Metoda razmjene vraća iste instance reda i stoga za te objekte ne bi bilo GC-a. Za razliku od bilo kojeg reda za blokiranje, izmjenjivač ne stvara čvorove ili objekte za držanje i dijeljenje podataka.

Stvaranje takvog cjevovoda slično je uzorku ometača, s ključnom razlikom, uzorak ometača podržava više proizvođača i potrošača, dok se izmjenjivač može koristiti između para potrošača i proizvođača.

4. Zaključak

Dakle, naučili smo što Izmjenjivač je u Javi, kako to radi, a vidjeli smo kako se koristi Izmjenjivač razred. Također, stvorili smo cjevovod i pokazali razmjenu podataka bez niti GC-a između niti.

Kao i uvijek, kôd je dostupan na GitHub-u.


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