LinkedBlockingQueue vs ConcurrentLinkedQueue

1. Introduksjon

LinkedBlockingQueue og ConcurrentLinkedQueue er de to mest brukte samtidskøene i Java. Selv om begge køene ofte brukes som samtidig datastruktur, er det subtile egenskaper og atferdsforskjeller mellom dem.

I denne korte veiledningen vil vi diskutere begge disse køene og forklare deres likheter og forskjeller.

2. LinkedBlockingQueue

De LinkedBlockingQueue er en valgfritt avgrenset blokkering av køimplementering, noe som betyr at køstørrelsen kan spesifiseres ved behov.

La oss lage en LinkedBlockingQueue som kan inneholde opptil 100 elementer:

BlockingQueue boundedQueue = ny LinkedBlockingQueue (100);

Vi kan også lage en ubegrenset LinkedBlockingQueue bare ved ikke å spesifisere størrelsen:

BlockingQueue unboundedQueue = ny LinkedBlockingQueue ();

En ubegrenset kø innebærer at størrelsen på køen ikke er spesifisert mens du oppretter. Derfor kan køen vokse dynamisk ettersom elementer blir lagt til den. Men hvis det ikke er noe minne igjen, kaster køen a java.lang.OutOfMemoryError.

Vi kan lage en LinkedBlockingQueue fra en eksisterende samling også:

Collection listOfNumbers = Arrays.asList (1,2,3,4,5); BlockingQueue queue = new LinkedBlockingQueue (listOfNumbers);

De LinkedBlockingQueue klasse implementerer BlockingQueue grensesnitt, som gir den blokkerende naturen til den.

En blokkeringskø indikerer at køen blokkerer tilgangstråden hvis den er full (når køen er avgrenset) eller blir tom. Hvis køen er full, vil legging av et nytt element blokkere tilgangstråden med mindre det er plass tilgjengelig for det nye elementet. Tilsvarende, hvis køen er tom, vil tilgang til et element blokkere ringetråden:

ExecutorService executorService = Executors.newFixedThreadPool (1); LinkedBlockingQueue kø = ny LinkedBlockingQueue (); executorService.submit (() -> {prøv {queue.take ();} fangst (InterruptedException e) {// unntakshåndtering}});

I kodebiten ovenfor får vi tilgang til en tom kø. derfor ta metoden blokkerer ringetråden.

Blokkeringsfunksjonen til LinkedBlockingQueue er forbundet med noen kostnader. Denne kostnaden er fordi hver sette eller ta operasjonen er i strid mellom produsenten eller forbrukertrådene. Derfor, i scenarier med mange produsenter og forbrukere, sette og iverksette tiltak kan være tregere.

3. ConcurrentLinkedQueue

EN ConcurrentLinkedQueueer en ubegrenset, trådsikker og ikke-blokkerende kø.

La oss lage en tom ConcurrentLinkedQueue:

ConcurrentLinkedQueue kø = ny ConcurrentLinkedQueue ();

Vi kan lage en ConcurrentLinkedQueue fra en eksisterende samling også:

Collection listOfNumbers = Arrays.asList (1,2,3,4,5); ConcurrentLinkedQueue kø = ny ConcurrentLinkedQueue (listOfNumbers);

I motsetning til en LinkedBlockingQueue,en ConcurrentLinkedQueue er en ikke-blokkerende kø. Dermed blokkerer den ikke en tråd når køen er tom. I stedet kommer den tilbake null. Siden det er ubegrenset, vil det kaste et java.lang.OutOfMemoryError hvis det ikke er noe ekstra minne for å legge til nye elementer.

Bortsett fra å være ikke-blokkerende, a ConcurrentLinkedQueue har ekstra funksjonalitet.

I ethvert produsent-forbrukerscenario vil forbrukere ikke nøye seg med produsenter; imidlertid vil flere produsenter kjempe med hverandre:

int element = 1; ExecutorService executorService = Executors.newFixedThreadPool (2); ConcurrentLinkedQueue kø = ny ConcurrentLinkedQueue (); Runnable offerTask = () -> queue.offer (element); Kallbar pollTask ​​= () -> {mens (queue.peek ()! = Null) {return queue.poll (). IntValue (); } returner null; }; executorService.submit (offerTask); Future returnElement = executorService.submit (pollTask); assertThat (returnElement.get (). intValue (), er (equalTo (element))); 

Den første oppgaven, offerTask, legger til et element i køen, og den andre oppgaven, pollTask, hente et element fra køen. Avstemningsoppgaven i tillegg sjekker køen for et element først som ConcurrentLinkedQueue er ikke-blokkerende og kan returnere a null verdi.

4. Likheter

Både LinkedBlockingQueue og ConcurrentLinkedQueue er køimplementeringer og deler noen vanlige egenskaper. La oss diskutere likhetene mellom disse to køene:

  1. Både implementerer Grensesnitt
  2. De begge bruk koblede noder for å lagre elementene sine
  3. Både er egnet for samtidige tilgangsscenarier

5. Forskjeller

Selv om begge disse køene har visse likheter, er det også store karakteristiske forskjeller:

TrekkLinkedBlockingQueueConcurrentLinkedQueue
Blokkerer naturenDet er en blokkerende kø og implementerer BlockingQueue grensesnittDet er en ikke-blokkerende kø og implementerer ikke BlockingQueue grensesnitt
KøstørrelseDet er en valgfri avgrenset kø, noe som betyr at det er bestemmelser for å definere køstørrelsen under opprettelsenDet er en ubegrenset kø, og det er ingen bestemmelse for å spesifisere køstørrelsen under opprettelsen
Låser naturenDet er en låsebasert køDet er en låsfri kø
AlgoritmeDen implementerer dens låsing basert på to-låskø algoritmeDet er avhengig av Michael & Scott algoritme for ikke-blokkerende, låsfrie køer
GjennomføringI to-låskø algoritmemekanisme, LinkedBlockingQueue bruker to forskjellige låser - putLock og takeLock . De sette / ta operasjoner bruker den første låsetypen, og ta / avstem operasjoner bruker den andre låsetypen Den bruker CAS (Compare-And-Swap)) for sin virksomhet
Blokkerende atferdDet er en blokkerende kø. Så det blokkerer tilgangstrådene når køen er tomDet blokkerer ikke tilgangstråden når køen er tom og returnerer null

6. Konklusjon

I denne artikkelen lærte vi om LinkedBlockingQueue og ConcurrentLinkedQueue.

Først diskuterte vi individuelt disse to køimplementeringene og noen av deres egenskaper. Så så vi likhetene mellom disse to køimplementeringene. Til slutt undersøkte vi forskjellene mellom disse to køimplementeringene.

Som alltid er kildekoden til eksemplene tilgjengelig på GitHub.


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