Úvod do synchronizovaných zbierok Java

1. Prehľad

Rámec zbierok je kľúčovou súčasťou Java. Poskytuje veľké množstvo rozhraní a implementácií, čo nám umožňuje priamo vytvárať a manipulovať s rôznymi typmi kolekcií.

Aj keď je použitie obyčajných nesynchronizovaných kolekcií celkovo jednoduché, pri práci vo viacvláknových prostrediach (tiež známe ako súbežné programovanie) sa môže stať skľučujúcim a náchylným na chyby.

Preto platforma Java poskytuje silnú podporu pre tento scenár prostredníctvom rôznych synchronizácií zavinovačky implementované v rámci Zbierky trieda.

Tieto obálky uľahčujú vytváranie synchronizovaných pohľadov na dodávané kolekcie pomocou niekoľkých statických výrobných metód.

V tomto návode hlboko sa do nich ponoríme obálky statickej synchronizácie. Zvýrazníme tiež rozdiel medzi synchronizovanými zbierkami a súbežnými zbierkami.

2. The synchronizedCollection () Metóda

Prvý synchronizačný obal, ktorý v tomto zaokrúhlení pokryjeme, je synchronizedCollection () metóda. Ako už názov napovedá, vráti kolekciu bezpečnú pre vlákna zálohovanú zadaným Zbierka.

Teraz, aby sme jasnejšie pochopili, ako používať túto metódu, vytvorme základný test jednotky:

Collection syncCollection = Collections.synchronizedCollection (nový ArrayList ()); Spustiteľné listOperations = () -> {syncCollection.addAll (Arrays.asList (1, 2, 3, 4, 5, 6)); }; Vlákno vlákno1 = nové vlákno (listOperations); Vlákno thread2 = nové vlákno (listOperations); thread1.start (); thread2.start (); thread1.join (); thread2.join (); assertThat (syncCollection.size ()). isEqualTo (12); } 

Ako je uvedené vyššie, vytvorenie synchronizovaného pohľadu na dodávanú kolekciu pomocou tejto metódy je veľmi jednoduché.

Aby sme demonštrovali, že metóda skutočne vracia kolekciu bezpečnú pre vlákna, najskôr vytvoríme niekoľko vlákien.

Potom si vpichneme a Spustiteľné inštancie do ich konštruktorov vo forme výrazu lambda. Pamätajme na to Spustiteľné je funkčné rozhranie, takže ho môžeme nahradiť výrazom lambda.

Na záver iba skontrolujeme, či každé vlákno efektívne pridáva do synchronizovanej kolekcie šesť prvkov, takže jeho konečná veľkosť je dvanásť.

3. The synchronizedList () Metóda

Rovnako, podobne ako synchronizedCollection () metódou, môžeme použiť synchronizedList () wrapper na vytvorenie synchronizovaného Zoznam.

Ako by sme mohli čakať, metóda vráti vlákno bezpečné zobrazenie zadaného Zoznam:

Zoznam syncList = Collections.synchronizedList (new ArrayList ());

Nie je prekvapením, že použitie synchronizedList () metóda vyzerá takmer rovnako ako jej náprotivok na vyššej úrovni, synchronizedCollection ().

Preto, ako sme to práve urobili v predchádzajúcom teste jednotky, raz sme vytvorili synchronizovaný Zoznam, môžeme vytvoriť niekoľko vlákien. Potom ich použijeme na prístup / manipuláciu s cieľom Zoznam spôsobom bezpečným pre vlákna.

Okrem toho, ak chceme iterovať cez synchronizovanú kolekciu a zabrániť neočakávaným výsledkom, mali by sme explicitne poskytnúť našu vlastnú implementáciu slučky bezpečnú pre vlákna. Preto by sme to mohli dosiahnuť použitím a synchronizované blok:

Zoznam syncCollection = Collections.synchronizedList (Arrays.asList ("a", "b", "c")); Zoznam uppercasedCollection = new ArrayList (); Spustiteľné listOperations = () -> {synchronizované (syncCollection) {syncCollection.forEach ((e) -> {uppercasedCollection.add (e.toUpperCase ());}); }}; 

Vo všetkých prípadoch, keď potrebujeme iterovať nad synchronizovanou kolekciou, by sme mali implementovať tento idióm. Je to tak preto, lebo iterácia synchronizovanej kolekcie sa vykonáva prostredníctvom viacerých hovorov do kolekcie. Preto ich treba vykonať ako jednu atómovú operáciu.

Využitie synchronizované blok zaisťuje atomicitu operácie.

4. The synchronizedMap () Metóda

The Zbierky trieda implementuje ďalší úhľadný synchronizačný obal, tzv synchronizedMap (). Mohli by sme ho použiť na ľahké vytvorenie synchronizovaného Mapa.

Metóda vracia dodávané zobrazenie bezpečné pre vlákna Mapa implementácia:

Map syncMap = Collections.synchronizedMap (nový HashMap ()); 

5. synchronizedSortedMap () Metóda

Existuje aj náprotivková implementácia synchronizedMap () metóda. To sa nazýva synchronizedSortedMap (), ktoré môžeme použiť na vytvorenie synchronizovaného SortedMap inštancia:

Map syncSortedMap = Collections.synchronizedSortedMap (nový TreeMap ()); 

6. synchronizedSet () Metóda

Ďalej, v tejto recenzii, máme synchronizedSet () metóda. Ako už z jeho názvu vyplýva, umožňuje nám vytvárať synchronizované Sady s minimálnym rozruchom.

Obal vráti kolekciu bezpečnú pre vlákna podporovanú zadaným Nastaviť:

Set syncSet = Collections.synchronizedSet (new HashSet ()); 

7. The synchronizedSortedSet () Metóda

Nakoniec je tu posledný synchronizačný obal, ktorý tu ukážeme synchronizedSortedSet ().

Podobne ako iné implementácie wrapperov, ktoré sme doteraz preskúmali, metóda vracia danú verziu bezpečnú pre vlákna Zoradené:

SortedSet syncSortedSet = Collections.synchronizedSortedSet (nový TreeSet ()); 

8. Synchronizované vs súčasné zbierky

Až do tohto okamihu sme sa bližšie pozreli na synchronizačné obaly rámca kolekcií.

Teraz sa zamerajme na rozdiely medzi synchronizovanými zbierkami a súbežnými zbierkami, ako napr ConcurrentHashMap a BlockingQueue implementácie.

8.1. Synchronizované zbierky

Synchronizované zbierky dosahujú bezpečnosť vlákien prostredníctvom vnútorného uzamknutia a celé zbierky sú uzamknuté. Vnútorné uzamykanie sa implementuje prostredníctvom synchronizovaných blokov v rámci metód zabalenej kolekcie.

Ako by sme mohli očakávať, synchronizované zbierky zabezpečujú konzistenciu / integritu údajov v prostrediach s viacerými vláknami. Môžu však prísť s pokutou za výkon, pretože ku kolekcii môže naraz pristupovať iba jedno vlákno (a.k.a. synchronizovaný prístup).

Podrobný návod na použitie synchronizované metódy a bloky, pozrite si náš článok na túto tému.

8.2. Súbežné zbierky

Súbežné zbierky (napr. ConcurrentHashMap), dosiahnuť bezpečnosť vlákien rozdelením ich údajov do segmentov. V ConcurrentHashMap, napríklad rôzne vlákna môžu získať zámky v každom segmente, takže viac vlákien môže pristupovať k Mapa súčasne (a.k.a. súbežný prístup).

Súbežné zbierky sú oveľa výkonnejšie ako synchronizované zbierky, kvôli inherentným výhodám súbežného prístupu k vláknam.

Takže výber toho, aký typ bezpečného zberu vlákien sa má použiť, závisí od požiadaviek každého prípadu použitia a podľa toho by sa mal vyhodnotiť.

9. Záver

V tomto článku sme sa podrobne zaoberali sadou synchronizačných wrapperov implementovaných v rámci Zbierky trieda.

Ďalej sme zdôraznili rozdiely medzi synchronizovanými a súbežnými kolekciami a tiež sme sa pozreli na prístupy, ktoré implementujú na dosiahnutie bezpečnosti vlákien.

Ako obvykle sú všetky ukážky kódu zobrazené v tomto článku k dispozícii na GitHub.


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