Java CyclicBarrier vs CountDownLatch
1. Úvod
V tomto výučbe to porovnáme CyclicBarrier a CountDownLatch a pokúsiť sa pochopiť podobnosti a rozdiely medzi nimi.
2. Čo sú to?
Pokiaľ ide o súbežnosť, môže byť náročné navrhnúť, čo má každý dosiahnuť.
V prvom rade oboje CountDownLatch a CyclicBarrier sa používajú na správu viacvláknových aplikácií.
A obidva sú určené na vyjadrenie toho, ako by dané vlákno alebo skupina vlákien malo čakať.
2.1. CountDownLatch
A CountDownLatch je konštrukt, ktorý je vláknom počkajje zapnutá, zatiaľ čo iné vlákna odpočítavať na západke, kým nedosiahne nulu.
Môžeme to považovať za jedlo v pripravovanej reštaurácii. Bez ohľadu na to, ktorý kuchár pripravuje, aj keď mnoho z nich n položiek, musí čašník počkaj kým nebudú všetky predmety na štítku. Ak tanier zaberie n predmety, každý kuchár bude odpočítavať na západke pre každú položku, ktorú položí na tanier.
2.2. CyclicBarrier
A CyclicBarrier je opakovane použiteľný konštrukt, kde je skupina vlákien čaká spolu, až kým nebudú všetky vlákna prísť. V tom okamihu je bariéra prelomená a akcia možno voliteľne vziať.
Môžeme o tom uvažovať ako o skupine priateľov. Zakaždým, keď majú v pláne jesť v reštaurácii, rozhodnú sa pre spoločný bod, kde sa môžu stretnúť. Oni počkaj jeden pre druhého tam, a len keď všetci prichádza môžu ísť do reštaurácie jesť spolu?
2.3. Ďalšie čítanie
A ak sa chcete dozvedieť viac podrobností o každej z týchto možností, pozrite si naše predchádzajúce návody CountDownLatch a CyclicBarrier resp.
3. Úlohy vs. vlákna
Poďme sa hlbšie ponoriť do niektorých sémantických rozdielov medzi týmito dvoma triedami.
Ako je uvedené v definíciách, CyclicBarrier umožňuje množstvu vlákien čakať na seba, zatiaľ čo CountDownLatch umožňuje jednému alebo viacerým vláknam čakať na dokončenie viacerých úloh.
V skratke, CyclicBarrier udržuje počet nite keďže CountDownLatch udržuje počet úlohy.
V nasledujúcom kóde definujeme a CountDownLatch s počtom dva. Ďalej voláme countDown () dvakrát z jedného vlákna:
CountDownLatch countDownLatch = nový CountDownLatch (2); Vlákno t = nové vlákno (() -> {countDownLatch.countDown (); countDownLatch.countDown ();}); t.start (); countDownLatch.await (); assertEquals (0, countDownLatch.getCount ());
Akonáhle západka dosiahne nulu, hovor na čakať vracia.
Upozorňujeme, že v tomto prípade mohli sme mať rovnaké vlákno dvakrát znížiť počet.
Cyklická bariéra, je v tomto bode iný.
Podobne ako v predchádzajúcom príklade, vytvoríme a Cyklická bariéra, opäť s počtom dva a zavolať čakať () na ňom, tentoraz z rovnakého vlákna:
CyclicBarrier cyklickýBariér = nový CyclicBarrier (2); Thread t = new Thread (() -> {try {cyclicBarrier.await (); cyclicBarrier.await ();} catch (InterruptedException | BrokenBarrierException e) {// error handling}}); t.start (); assertEquals (1, cyclicBarrier.getNumberWaiting ()); assertFalse (cyclicBarrier.isBroken ());
Prvý rozdiel tu spočíva v tom, že vlákna, ktoré čakajú, sú samy osebe bariérou.
Po druhé, a čo je dôležitejšie, druhy čakať () je zbytočné. Jedno vlákno nemôže odpočítavať bariéra dvakrát.
Skutočne, pretože t musieť počkaj pre ďalšie vlákno na volanie čakať () - zvýšiť počet na dva - tDruhý hovor na číslo čakať () nebude v skutočnosti vyvolané, kým nebude bariéra už prelomená!
V našom teste bariéra nebola prekročená, pretože nás čaká iba jedno vlákno a nie dve vlákna, ktoré by boli potrebné na spustenie bariéry. Je to zrejmé aj z cyclicBarrier.isBroken () metóda, ktorá sa vráti nepravdivé.
4. Opätovná použiteľnosť
Druhým najzrejmejším rozdielom medzi týmito dvoma triedami je opätovné použitie. Rozpracovať, keď bariéra zakopne CyclicBarrier, počet sa nastaví na pôvodnú hodnotu.CountDownLatch sa líši, pretože počet sa nikdy nevynuluje.
V danom kóde definujeme a CountDownLatch s počtom 7 a počítať to cez 20 rôznych hovorov:
CountDownLatch countDownLatch = nový CountDownLatch (7); ExecutorService es = Executors.newFixedThreadPool (20); for (int i = 0; i {long prevValue = countDownLatch.getCount (); countDownLatch.countDown (); if (countDownLatch.getCount ()! = prevValue) {outputScraper.add ("Počet aktualizovaný");}}); } es.shutdown (); assertTrue (outputScraper.size () <= 7);
Poznamenávame, že aj keď volá 20 rôznych vlákien countDown (), počet sa nevynuluje, akonáhle dosiahne nulu.
Podobne ako v predchádzajúcom príklade definujeme a CyclicBarrier s počtom 7 a počkajte na to z 20 rôznych vlákien:
CyclicBarrier cyklickýBariér = nový CyclicBarrier (7); ExecutorService es = Executors.newFixedThreadPool (20); for (int i = 0; i {try {if (cyclicBarrier.getNumberWaiting () 7);
V tomto prípade pozorujeme, že hodnota klesá zakaždým, keď sa spustí nové vlákno, resetovaním na pôvodnú hodnotu, akonáhle dosiahne nulu.
5. Záver
Všetko vo všetkom, CyclicBarrier a CountDownLatchsú užitočné nástroje na synchronizáciu medzi viacerými vláknami. Z hľadiska funkčnosti, ktorú poskytujú, sa však zásadne líšia. Pri výbere, ktorý je pre danú prácu vhodný, každú dobre zvážte.
Ako obvykle, všetky diskutované príklady sú prístupné na Githube.