Úvod do výmenníka v Jave

1. Prehľad

V tejto príručke sa pozrieme na to java.util.concurrent.exchanger. To funguje ako spoločný bod pre dve vlákna v Jave na vzájomnú výmenu objektov medzi nimi.

2. Úvod do výmenníka

The Výmenník triedy v Jave je možné použiť na zdieľanie objektov medzi dvoma vláknami typu T. Trieda poskytuje iba jednu preťaženú metódu výmena (T t).

Pri vyvolaní výmena čaká, kým to zavolá aj druhé vlákno v páre. V tomto okamihu druhé vlákno zistí, že prvé vlákno čaká so svojim objektom. Niť vymieňa predmety, ktoré držia, signalizuje ich výmenu a teraz sa môžu vrátiť.

Pozrime sa na príklad, aby sme pochopili výmenu správ medzi dvoma vláknami s Výmenník:

@ Test public void givenThreads_whenMessageExchanged_thenCorrect () {Výmenník výmenníka = nový Výmenník (); Runnable taskA = () -> {try {String message = exchanger.exchange ("from A"); assertEquals ("z B", správa); } catch (InterruptedException e) {Thread.currentThread.interrupt (); hodiť novú RuntimeException (e); }}; Runnable taskB = () -> {try {String message = exchanger.exchange ("from B"); assertEquals ("z A", správa); } catch (InterruptedException e) {Thread.currentThread.interrupt (); hodiť novú RuntimeException (e); }}; CompletableFuture.allOf (runAsync (taskA), runAsync (taskB)). Join (); }

Tu máme dve vlákna, ktoré si medzi sebou vymieňajú správy pomocou spoločného výmenníka. Pozrime sa na príklad, keď vymieňame objekt z hlavného vlákna za nové vlákno:

@ Test public void givenThread_WhenExchangedMessage_thenCorrect () vyvolá InterruptedException {výmenník výmenníka = nový výmenník (); Runnable runner = () -> {try {String message = exchanger.exchange ("from runner"); assertEquals ("bežcovi", správa); } catch (InterruptedException e) {Thread.currentThread.interrupt (); hodiť novú RuntimeException (e); }}; Výsledok CompletableFuture = CompletableFuture.runAsync (bežec); Reťazec msg = exchanger.exchange ("na bežca"); assertEquals ("od bežca", správa); result.join (); }

Upozorňujeme, že musíme začať bežec najskôr a neskôr zavolajte výmena () v hlavnom vlákne.

Upozorňujeme tiež, že volanie prvého vlákna môže vypršať, ak druhé vlákno nedosiahne čas výmeny. Ako dlho má prvé vlákno čakať, je možné ovládať pomocou preťaženia výmena (T t, long timeout, TimeUnit timeUnit).

3. Žiadna výmena údajov GC

Výmenník by sa dalo použiť na vytvorenie potrubného typu vzorov s prenosom údajov z jedného vlákna do druhého. V tejto časti vytvoríme jednoduchý stoh vlákien, ktoré si medzi sebou nepretržite odovzdávajú dáta ako kanál.

@Test public void givenData_whenPassedThrough_thenCorrect () vyvolá InterruptedException {výmenník readerExchanger = nový výmenník (); Výmenník writerExchanger = nový výmenník (); Spustiteľná čítačka = () -> {Queue readerBuffer = nový ConcurrentLinkedQueue (); while (true) {readerBuffer.add (UUID.randomUUID (). toString ()); if (readerBuffer.size ()> = BUFFER_SIZE) {readerBuffer = readerExchanger.exchange (readerBuffer); }}}; Spustiteľný procesor = () -> {Queue processorBuffer = new ConcurrentLinkedQueue (); Queue writerBuffer = new ConcurrentLinkedQueue (); processorBuffer = readerExchanger.exchange (processorBuffer); while (true) {writerBuffer.add (processorBuffer.poll ()); if (processorBuffer.isEmpty ()) {processorBuffer = readerExchanger.exchange (processorBuffer); writerBuffer = writerExchanger.exchange (writerBuffer); }}}; Spustiteľný spisovateľ = () -> {Queue writerBuffer = nový ConcurrentLinkedQueue (); writerBuffer = writerExchanger.exchange (writerBuffer); while (true) {System.out.println (writerBuffer.poll ()); if (writerBuffer.isEmpty ()) {writerBuffer = writerExchanger.exchange (writerBuffer); }}}; CompletableFuture.allOf (runAsync (čítačka), runAsync (procesor), runAsync (zapisovateľ)). Join (); }

Tu máme tri vlákna: čitateľ, procesora spisovateľka. Spoločne fungujú ako jeden kanál, ktorý si medzi sebou vymieňa údaje.

The čítačka Výmenník je zdieľaný medzi čitateľ a procesor vlákno, zatiaľ čo spisovateľ Výmenník je zdieľaná medzi procesor a spisovateľka závit.

Uvedený príklad slúži iba na demonštráciu. Pri vytváraní nekonečných slučiek pomocou musíme byť opatrní while (true). Kvôli zachovaniu čitateľnosti kódu sme vynechali niektoré úpravy výnimiek.

Tento vzorec výmeny údajov pri opätovnom použití vyrovnávacej pamäte umožňuje mať menšie množstvo odpadu. Metóda výmeny vráti rovnaké inštancie frontu, a preto by pre tieto objekty neexistoval žiadny GC. Na rozdiel od akejkoľvek blokujúcej fronty výmenník nevytvára žiadne uzly alebo objekty na uchovávanie a zdieľanie údajov.

Vytvorenie takého plynovodu je podobné ako pri schéme narušenia, s hlavným rozdielom, schéma prerušenia podporuje viacerých výrobcov a spotrebiteľov, zatiaľ čo výmenník by sa mohol použiť medzi dvojicou spotrebiteľov a výrobcov.

4. Záver

Takže sme sa dozvedeli čo Výmenník je v Jave, ako to funguje, a videli sme, ako používať Výmenník trieda. Tiež sme vytvorili kanál a demonštrovali výmenu dát medzi vláknami bez GC.

Ako vždy, kód je k dispozícii na GitHub.


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