Vodič za istodobne redove u Javi

1. Pregled

U ovom uputstvu proći ćemo kroz neke od glavnih implementacija istodobnih redova u Javi. Općeniti uvod u redove potražite u našem Vodiču za Javu Red Članak o sučelju.

2. Redovi

U višenitnim aplikacijama, redovi moraju obrađivati ​​više istodobnih scenarija proizvođača i potrošača. Ispravan odabir istodobnog reda mogao bi biti presudan za postizanje dobrih performansi u našim algoritmima.

Prvo ćemo vidjeti neke važne razlike između reda za blokiranje i one koji ne blokira. Zatim ćemo pogledati neke implementacije i najbolje prakse.

2. Blokiranje u odnosu na red koji ne blokira

BlockingQueue ponude jednostavan mehanizam siguran za konac. U ovom redu, niti moraju čekati dostupnost reda. Proizvođači će pričekati dostupni kapacitet prije dodavanja elemenata, dok će potrošači čekati dok se red ne isprazni. U tim će slučajevima neblokirajući red ili izbaciti iznimku ili će vratiti posebnu vrijednost, na primjer null ili lažno.

Da bi postigao ovaj mehanizam blokiranja, BlockingQueue sučelje izlaže dvije funkcije povrh normalne Red funkcije: staviti i uzeti. Te su funkcije jednake dodati i ukloniti u standardu Red.

3. Istovremeno Red Provedbe

3.1. ArrayBlockingQueue

Kao što mu samo ime govori, ovaj red interno koristi niz. Kao posljedica toga jest ograničeni red, što znači da ima fiksnu veličinu.

Jednostavan radni red primjer je slučaja upotrebe. Ovaj je scenarij često nizak omjer proizvođača i potrošača, gdje zadatke koji oduzimaju vrijeme dijelimo na više radnika. Budući da ovaj red ne može rasti u nedogled, ograničenje veličine djeluje kao sigurnosni prag ako je problem s memorijom.

Kad smo već kod memorije, važno je napomenuti da red čekanja unaprijed raspoređuje niz. Iako ovo može poboljšati protok, to također može potrošiti više memorije nego što je potrebno. Na primjer, red velikog kapaciteta može ostati prazan dulje vrijeme.

Također, ArrayBlockingQueue koristi jednu bravu za oboje staviti i uzeti operacijama. To osigurava da se ne prepišu unosi po cijenu uspješnosti.

3.2. LinkedBlockingQueue

The LinkedBlockingQueue koristi a LinkedList varijanta, gdje je svaka stavka reda novi čvor. Iako ovo u principu čini red neograničenim, još uvijek ima tvrdu granicu od Cijeli broj.MAX_VALUE.

S druge strane, veličinu reda možemo postaviti pomoću konstruktora LinkedBlockingQueue (int kapacitet).

Ovaj red koristi različite brave za staviti i uzeti operacijama. Kao posljedica toga, obje se operacije mogu raditi paralelno i poboljšati protok.

Budući da je LinkedBlockingQueue može biti ograničeno ili neograničeno, zašto bismo koristili ArrayBlockingQueue preko ovog? LinkedBlockingQueue treba dodijeliti i osloboditi čvorove svaki put kad se stavka doda ili ukloni iz reda. Iz tog razloga, an ArrayBlockingQueue može biti bolja alternativa ako red brzo raste i brzo se smanjuje.

Izvedba LinkedBlockingQueue je rečeno da je nepredvidljiv. Drugim riječima, uvijek moramo profilirati svoje scenarije kako bismo osigurali da koristimo ispravnu strukturu podataka.

3.3. PriorityBlockingQueue

The PriorityBlockingQueue je naše rješenje kada moramo konzumirati predmete u određenom redoslijedu. Da bi to postigao, PriorityBlockingQueue koristi binarnu hrpu temeljenu na nizu.

Iako interno koristi jedan mehanizam zaključavanja, uzeti operacija se može dogoditi istodobno s staviti operacija. Korištenje jednostavne blokade okretaja to omogućava.

Tipičan slučaj upotrebe su konzumiranje zadataka s različitim prioritetima. Ne želimo da zadatak niskog prioriteta zamijeni zadatak visokog prioriteta.

3.4. DelayQueue

Koristimo a DelayQueuekada potrošač može uzeti samo predmet kojem je istekao rok trajanja. Zanimljivo je da koristi a PriorityQueue interno za naručivanje predmeta po isteku.

Budući da ovo nije općeniti red, on ne pokriva toliko scenarija kao ArrayBlockingQueue ili LinkedBlockingQueue. Na primjer, ovaj red možemo koristiti za implementaciju jednostavne petlje događaja slične onoj koja se nalazi u NodeJS-u. Asinhrone zadatke postavljamo u red za kasniju obradu kada isteknu.

3.5. LinkedTransferQueue

The LinkedTransferQueue uvodi a prijenos metoda. Dok se drugi redovi obično blokiraju prilikom proizvodnje ili konzumiranja predmeta, LinkedTransferQueueomogućuje proizvođaču da pričeka potrošnju predmeta.

Koristimo a LinkedTransferQueue kada trebamo jamstvo da je određeni predmet koji stavimo u red netko preuzeo. Također, pomoću ovog reda možemo implementirati jednostavan algoritam povratnog tlaka. Zapravo, blokiranjem proizvođača do potrošnje, potrošači mogu upravljati protokom proizvedenih poruka.

3.6. SynchronousQueue

Iako redovi obično sadrže mnogo predmeta, SynchronousQueue uvijek će imati najviše jedan predmet. Drugim riječima, moramo vidjeti SynchronousQueue kao jednostavan način razmjene nekih podataka između dvije niti.

Kada imamo dvije niti kojima je potreban pristup zajedničkom stanju, često ih sinkroniziramo s CountDownLatch ili drugi mehanizmi sinkronizacije. Korištenjem a SynchronousQueue, možemo izbjegavajte ovu ručnu sinkronizaciju niti.

3.7. ConcurrentLinkedQueue

The ConcurrentLinkedQueue je jedini neblokirajući red u ovom vodiču. Slijedom toga, pruža algoritam "bez čekanja" gdje dodati i anketa zajamčeno je da su zaštićeni niti i odmah se vraćaju. Umjesto brava, ovaj red koristi CAS (Usporedi i zamijeni).

Interno se temelji na algoritmu tvrtke Jednostavno, brzo i praktično neblokiranje i blokiranje istodobnih algoritama reda Mageda M. Michael i Michael L. Scott.

To je savršen kandidat za moderne reaktivne sustave, gdje je često zabranjeno korištenje blokadnih struktura podataka.

S druge strane, ako naš potrošač završi s čekanjem, vjerojatno bismo trebali odabrati blokirajući red kao bolju alternativu.

4. Zaključak

U ovom smo vodiču prošetali različitim istodobnim implementacijama reda, raspravljajući o njihovim snagama i slabostima. Imajući to na umu, bolje smo opremljeni za razvoj učinkovitih, trajnih i dostupnih sustava.


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