Java CyclicBarrier vs CountDownLatch

1. Introduksjon

I denne opplæringen vil vi sammenligne CyclicBarrier og CountDownLatch og prøv å forstå likhetene og forskjellene mellom de to.

2. Hva er dette?

Når det gjelder samtidighet, kan det være utfordrende å konseptualisere hva hver enkelt er ment å oppnå.

Først og fremst begge deler CountDownLatch og CyclicBarrier brukes til å administrere applikasjoner med flere tråder.

Og, de er begge ment for å uttrykke hvordan en gitt tråd eller gruppe av tråder skal vente.

2.1. CountDownLatch

EN CountDownLatch er en konstruksjon som en tråd ventes på mens andre tråder telle ned på låsen til den når null.

Vi kan tenke på dette som en rett på en restaurant som tilberedes. Uansett hvilken kokk som forbereder imidlertid mange av n gjenstander, må servitøren vente til alle elementene er på tallerkenen. Hvis en plate tar n gjenstander, vil enhver kokk telle ned på låsen for hvert element hun legger på tallerkenen.

2.2. CyclicBarrier

EN CyclicBarrier er en gjenbrukbar konstruksjon der en gruppe tråder venter sammen til alle trådene ankomme. På det tidspunktet er barrieren brutt og en handling kan eventuelt tas.

Vi kan tenke på dette som en vennegjeng. Hver gang de planlegger å spise på en restaurant, bestemmer de et felles punkt hvor de kan møtes. De vente for hverandre der, og bare når alle ankommer kan de gå til restauranten for å spise sammen.

2.3. Videre lesning

Og for mye mer detaljert informasjon om hver av disse individuelt, se våre tidligere veiledninger om CountDownLatch og CyclicBarrier henholdsvis.

3. Oppgaver vs. tråder

La oss ta et dypere dykk inn i noen av de semantiske forskjellene mellom disse to klassene.

Som nevnt i definisjonene, CyclicBarrier lar et antall tråder vente på hverandre, mens CountDownLatch lar en eller flere tråder vente på at en rekke oppgaver skal fullføres.

Kort oppsummert, CyclicBarrier opprettholder en telling av tråder mens CountDownLatch opprettholder en telling av oppgaver.

I den følgende koden definerer vi a CountDownLatch med en telling på to. Deretter ringer vi countDown () to ganger fra en enkelt tråd:

CountDownLatch countDownLatch = ny CountDownLatch (2); Tråd t = ny tråd (() -> {countDownLatch.countDown (); countDownLatch.countDown ();}); t.start (); countDownLatch.await (); assertEquals (0, countDownLatch.getCount ());

Når låsen når null, kalles til avvente returnerer.

Vær oppmerksom på at i dette tilfellet vi var i stand til å ha samme tråd redusere antallet to ganger.

Syklisk barriere, skjønt, er forskjellig på dette punktet.

I likhet med eksemplet ovenfor, oppretter vi en Syklisk barriere, igjen med en telling på to og ring avvente() på den, denne gangen fra samme tråd:

CyclicBarrier cyclicBarrier = ny CyclicBarrier (2); Tråd t = ny tråd (() -> {prøv {cyclicBarrier.await (); cyclicBarrier.await ();} fangst (InterruptedException | BrokenBarrierException e) {// feilhåndtering}}); t.start (); assertEquals (1, cyclicBarrier.getNumberWaiting ()); assertFalse (cyclicBarrier.isBroken ());

Den første forskjellen her er at trådene som venter i seg selv er barrieren.

For det andre, og enda viktigere, den andre avvente() er ubrukelig. En enkelt tråd kan ikke telle ned en barriere to ganger.

Faktisk fordi tvente for en annen tråd å ringe avvente() - å bringe tellingen til to - t’S andre samtale til avvente() vil faktisk ikke påberopes før barrieren allerede er brutt!

I vår test, barrieren er ikke krysset fordi vi bare har en tråd som venter og ikke de to trådene som kreves for at barrieren skal utløses. Dette fremgår også av cyclicBarrier.isBroken () metode, som returnerer falsk.

4. Gjenbrukbarhet

Den nest tydeligste forskjellen mellom disse to klassene er gjenbrukbarhet. Å utdype, når bommen treffer inn CyclicBarrier, tilbakestilles tellingen til den opprinnelige verdien.CountDownLatch er annerledes fordi tellingen aldri tilbakestilles.

I den gitte koden definerer vi a CountDownLatch med telling 7 og tell den gjennom 20 forskjellige samtaler:

CountDownLatch countDownLatch = ny CountDownLatch (7); ExecutorService es = Executors.newFixedThreadPool (20); for (int i = 0; i {long prevValue = countDownLatch.getCount (); countDownLatch.countDown (); if (countDownLatch.getCount ()! = prevValue) {outputScraper.add ("Count Updated");}}); } es.utkobling (); assertTrue (outputScraper.size () <= 7);

Vi observerer at selv om 20 forskjellige tråder ringer countDown (), teller ikke tellingen når den når null.

I likhet med eksemplet ovenfor definerer vi a CyclicBarrier med telling 7 og vent på den fra 20 forskjellige tråder:

CyclicBarrier cyclicBarrier = ny CyclicBarrier (7); ExecutorService es = Executors.newFixedThreadPool (20); for (int i = 0; jeg {prøver {if (cyclicBarrier.getNumberWaiting () 7);

I dette tilfellet observerer vi at verdien synker hver gang en ny tråd går, ved å tilbakestille til den opprinnelige verdien når den når null.

5. Konklusjon

Alt i alt, CyclicBarrier og CountDownLatcher begge nyttige verktøy for synkronisering mellom flere tråder. Imidlertid er de fundamentalt forskjellige når det gjelder funksjonaliteten de gir. Vurder hver enkelt nøye når du avgjør hvilken som er riktig for jobben.

Som vanlig kan du se alle eksemplene på Github.


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