LinkedBlockingQueue vs ConcurrentLinkedQueue

1. Úvod

LinkedBlockingQueue a ConcurrentLinkedQueue sú dva najčastejšie používané súbežné fronty v Jave. Aj keď sa oba fronty často používajú ako súbežná dátová štruktúra, existujú medzi nimi jemné charakteristiky a rozdiely v správaní.

V tomto krátkom tutoriáli si prediskutujeme obidve tieto fronty a vysvetlíme ich podobnosti a rozdiely.

2. LinkedBlockingQueue

The LinkedBlockingQueue je voliteľne ohraničené implementácia blokujúceho frontu, čo znamená, že v prípade potreby je možné určiť veľkosť frontu.

Vytvorme a LinkedBlockingQueue ktoré môžu obsahovať až 100 prvkov:

BlockingQueue boundedQueue = nová LinkedBlockingQueue (100);

Môžeme tiež vytvoriť neobmedzené LinkedBlockingQueue len nezadaním veľkosti:

BlockingQueue unboundedQueue = nový LinkedBlockingQueue ();

Neohraničený front znamená, že pri vytváraní nie je zadaná veľkosť frontu. Poradie preto môže rásť dynamicky, keď sa doň pridávajú prvky. Ak však nezostane žiadna pamäť, potom fronta hodí a java.lang.OutOfMemoryError.

Môžeme vytvoriť LinkedBlockingQueue aj z existujúcej zbierky:

Zbierka listOfNumbers = Arrays.asList (1,2,3,4,5); Fronta BlockingQueue = nová LinkedBlockingQueue (listOfNumbers);

The LinkedBlockingQueue trieda realizuje BlockingQueue rozhranie, ktoré mu poskytuje blokujúcu povahu.

Blokovacia fronta označuje, že fronta blokuje prístupové vlákno, ak je plné (keď je front ohraničený) alebo sa stane prázdnym. Ak je poradie plné, pridanie nového prvku zablokuje prístupové vlákno, pokiaľ pre nový prvok nebude k dispozícii miesto. Podobne, ak je front prázdny, prístup k prvku blokuje volajúce vlákno:

ExecutorService executorService = Executors.newFixedThreadPool (1); LinkedBlockingQueue queue = nový LinkedBlockingQueue (); executorService.submit (() -> {try {queue.take ();} catch (InterruptedException e) {// handling handling}});

Vo vyššie uvedenom útržku kódu vstupujeme do prázdneho frontu. Preto vziať metóda blokuje volajúce vlákno.

Funkcia blokovania LinkedBlockingQueue je spojená s určitými nákladmi. Táto cena je preto, že každý dať alebo vziať operácia je zablokovaná medzi vláknami výrobcu alebo spotrebiteľa. Preto v scenároch s mnohými výrobcami a spotrebiteľmi dať a prijať opatrenia môžu byť pomalšie.

3. ConcurrentLinkedQueue

A ConcurrentLinkedQueueje neobmedzený, bezpečný pre vlákna a neblokujúci front.

Vytvorme prázdny ConcurrentLinkedQueue:

Fronta ConcurrentLinkedQueue = nová ConcurrentLinkedQueue ();

Môžeme vytvoriť ConcurrentLinkedQueue aj z existujúcej zbierky:

Zbierka listOfNumbers = Arrays.asList (1,2,3,4,5); Fronta ConcurrentLinkedQueue = nová ConcurrentLinkedQueue (listOfNumbers);

Na rozdiel od a LinkedBlockingQueue,a ConcurrentLinkedQueue je neblokujúci rad. Neblokuje teda vlákno, akonáhle je rad prázdny. Namiesto toho sa vráti nulový. Pretože je neobmedzený, hodí java.lang.OutOfMemoryError ak nie je dostatok pamäte na pridanie nových prvkov.

Okrem toho, že neblokuje, a ConcurrentLinkedQueue má ďalšie funkcie.

V žiadnom scenári medzi výrobcom a spotrebiteľom sa spotrebitelia neuspokoja s výrobcami; Viacerí producenti si však budú navzájom odporovať:

int prvok = 1; ExecutorService executorService = Executors.newFixedThreadPool (2); Fronta ConcurrentLinkedQueue = nová ConcurrentLinkedQueue (); Spustiteľný offerTask = () -> queue.offer (element); Vyžiadateľná pollTask ​​= () -> {while (queue.peek ()! = Null) {návratová fronta.poll (). IntValue (); } return null; }; executorService.submit (offerTask); Future returnsElement = executorService.submit (pollTask); assertThat (returnedElement.get (). intValue (), is (equalTo (element))); 

Prvá úloha, offerTask, pridá do fronty prvok a druhá úloha, pollTask, načítať prvok z frontu. Anketa navyše najskôr skontroluje poradie prvku ako ConcurrentLinkedQueue neblokuje a môže vrátiť a nulový hodnotu.

4. Podobnosti

Oboje LinkedBlockingQueue a ConcurrentLinkedQueue sú implementácie frontu a zdieľajú niektoré spoločné charakteristiky. Poďme diskutovať o podobnosti týchto dvoch frontov:

  1. Oboje realizuje Fronta Rozhranie
  2. Obaja používať prepojené uzly na ukladanie ich prvkov
  3. Oboje sú vhodné pre scenáre súbežného prístupu

5. Rozdiely

Aj keď majú obe tieto fronty určité podobnosti, existujú aj podstatné rozdiely v charakteristikách:

FunkciaLinkedBlockingQueueConcurrentLinkedQueue
Blokovanie prírodyJe to blokujúca fronta a implementuje sa do nej BlockingQueue rozhranieJe to neblokujúci front a neimplementuje BlockingQueue rozhranie
Veľkosť frontuJe to voliteľne ohraničený front, čo znamená, že existujú ustanovenia na definovanie veľkosti frontu počas vytváraniaJedná sa o neobmedzený front a počas vytvárania neexistuje žiadne ustanovenie, ktoré by určovalo veľkosť frontu
Zamykanie prírodyto je frontu založenú na zámkochto je frontu bez zámkov
AlgoritmusRealizuje jeho zamykanie na základe dvojzámkový rad algoritmusSpolieha sa na Algoritmus Michaela a Scotta pre neblokujúce fronty bez blokovania
ImplementáciaV dvojzámkový rad mechanizmus algoritmu, LinkedBlockingQueue používa dva rôzne zámky - putLock a takeLock . The dať / vziať operácie používa prvý typ zámku a vziať / hlasovať operácie používajú iný typ zámku Používa CAS (Compare-And-Swap) pre svoju činnosť
Blokovacie správanieJe to blokujúci rad. Blokuje teda prístupové vlákna, keď je rad prázdnyNeblokuje prístupové vlákno, keď je rad prázdny a vráti sa nulový

6. Záver

V tomto článku sme sa dozvedeli o LinkedBlockingQueue a ConcurrentLinkedQueue.

Najprv sme individuálne diskutovali o týchto dvoch implementáciách frontu a niektorých ich charakteristikách. Potom sme videli podobnosti medzi týmito dvoma implementáciami frontu. Nakoniec sme preskúmali rozdiely medzi týmito dvoma implementáciami front.

Zdrojový kód príkladov je ako vždy k dispozícii na serveri GitHub.


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