Java CyclicBarrier vs CountDownLatch

1. Uvod

U ovom ćemo uputstvu usporediti CyclicBarrier i CountDownLatch i pokušajte razumjeti sličnosti i razlike između njih dvoje.

2. Što su to?

Što se tiče podudarnosti, može biti izazov konceptualizirati ono što je svaka od njih trebala postići.

Prvo i najvažnije, oboje CountDownLatch i CyclicBarrier koriste se za upravljanje višenitnim aplikacijama.

I, oboje imaju za cilj izraziti kako određena nit ili skupina niti treba čekati.

2.1. CountDownLatch

A CountDownLatch je konstrukcija koja nit čekatis na dok druge niti odbrojavati na zasunu dok ne dosegne nulu.

Možemo to zamisliti kao jelo u restoranu koje se priprema. Bez obzira koji kuhar priprema koliko god n predmeta, konobar mora čekati dok se svi predmeti ne nađu na tanjuru. Ako tanjur uzme n predmeta, hoće svaki kuhar odbrojavati na zasunu za svaki predmet koji stavi na tanjur.

2.2. CyclicBarrier

A CyclicBarrier je konstrukcija za višekratnu uporabu gdje skupina niti čeka zajedno dok sve niti stići. U tom je trenutku prepreka slomljena i akcijski može se po želji uzeti.

O ovome možemo razmišljati kao o grupi prijatelja. Svaki put kad planiraju jesti u restoranu, odluče zajedničku točku na kojoj se mogu naći. Oni čekati jedno za drugo tamo i to samo kad svi stiže mogu li ići u restoran jesti zajedno.

2.3. Daljnje čitanje

A za puno više detalja o svakom od njih pojedinačno, pogledajte naše prethodne vodiče o CountDownLatch i CyclicBarrier odnosno.

3. Zadaci nasuprot niti

Krenimo dublje u neke semantičke razlike između ove dvije klase.

Kao što je navedeno u definicijama, CyclicBarrier omogućuje brojnim nitima da čekaju jedna na drugu, dok CountDownLatch omogućuje jednoj ili više niti da pričekaju dovršavanje određenog broja zadataka.

Ukratko, CyclicBarrier održava brojanje od niti dok CountDownLatch održava brojanje od zadaci.

U sljedećem kodu definiramo a CountDownLatch s brojanjem do dva. Dalje, zovemo countDown () dva puta iz jedne niti:

CountDownLatch countDownLatch = novo CountDownLatch (2); Tema t = nova nit (() -> {countDownLatch.countDown (); countDownLatch.countDown ();}); t.start (); countDownLatch.await (); assertEquals (0, countDownLatch.getCount ());

Jednom kada zasun dosegne nulu, poziv na čekati vraća se.

Imajte na umu da u ovom slučaju, uspjeli smo da ista nit dva puta smanji broj.

CyclicBarrier, međutim, po ovom pitanju je drugačije.

Slično gore navedenom primjeru, kreiramo a CyclicBarrier, opet s brojem dva i nazovite čekati() na njemu, ovaj put iz iste niti:

CyclicBarrier cyclicBarrier = nova CyclicBarrier (2); Tema t = nova nit (() -> {try {cyclicBarrier.await (); cyclicBarrier.await ();} catch (InterruptedException | BrokenBarrierException e) {// rukovanje pogreškama}}); t.start (); assertEquals (1, cyclicBarrier.getNumberWaiting ()); assertFalse (cyclicBarrier.isBroken ());

Prva razlika ovdje je što su niti koje čekaju same sebi prepreka.

Drugo, i što je još važnije, drugi čekati() je beskorisno. Jedna nit ne može odbrojavati dva puta barijeru.

Doista, jer t mora čekati za još jednu nit koju treba nazvati čekati() - da brojanje dovedem do dva - t‘Drugi poziv čekati() zapravo se neće pozivati ​​dok barijera već nije slomljena!

U našem testu, prepreka nije pređena jer imamo samo jednu nit koja čeka, a ne dvije niti koje bi bile potrebne da bi se prepreka spotaknula. To je također vidljivo iz cyclicBarrier.isBroken () metoda, koja se vraća lažno.

4. Ponovna upotrebljivost

Druga najočitija razlika između ove dvije klase je ponovna upotrebljivost. Da razradim, kad se prepreka spotakne CyclicBarrier, broj se vraća na izvornu vrijednost.CountDownLatch je različit jer se brojanje nikad ne resetira.

U danom kodu definiramo a CountDownLatch s brojem 7 i prebrojite ga kroz 20 različitih poziva:

CountDownLatch countDownLatch = novi 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.shutdown (); assertTrue (outputScraper.size () <= 7);

Primjećujemo to iako poziva 20 različitih niti countDown (), brojanje se ne resetira kad dosegne nulu.

Slično gornjem primjeru, definiramo i CyclicBarrier s brojem 7 i pričekajte na njemu iz 20 različitih niti:

CyclicBarrier cyclicBarrier = novi CyclicBarrier (7); ExecutorService es = Executors.newFixedThreadPool (20); for (int i = 0; i {try {if (cyclicBarrier.getNumberWaiting () 7);

U ovom slučaju primjećujemo da se vrijednost smanjuje svaki put kad se pokrene nova nit, resetiranjem na izvornu vrijednost, nakon što dosegne nulu.

5. Zaključak

Sve u svemu, CyclicBarrier i CountDownLatchkorisni su alati za sinkronizaciju između više niti. Međutim, oni se bitno razlikuju u pogledu funkcionalnosti koju pružaju. Razmotrite svaki pažljivo kad utvrđujete koji je pravi posao.

Kao i obično, svim raspravljenim primjerima može se pristupiti na Githubu.