Sprievodca po CopyOnWriteArrayList

1. Prehľad

V tomto rýchlom článku sa pozrieme na CopyOnWriteArrayList z java.util.concurrent balíček.

Toto je veľmi užitočný konštrukt vo viacvláknových programoch - keď chceme iterovať zoznam bezpečným spôsobom bez explicitnej synchronizácie.

2. CopyOnWriteArrayList API

Dizajn CopyOnWriteArrayList používa zaujímavú techniku, vďaka ktorej je zabezpečená bezpečnosť vlákien bez potreby synchronizácie. Keď používame niektorú z metód úprav - ako napr pridať () alebo odstrániť () - celý obsah CopyOnWriteArrayList sa skopíruje do novej internej kópie.

Vďaka tejto jednoduchej skutočnosti môžeme zoznam iterovať bezpečným spôsobom, aj keď dochádza k súbežnej úprave.

Keď voláme iterátor () metóda na CopyOnWriteArrayList, vrátime sa Iterátor zálohované nezmeniteľnou snímkou ​​obsahu CopyOnWriteArrayList.

Jeho obsahom je presná kópia údajov, ktoré sa nachádzajú vo vnútri ArrayList od doby, kedy Iterátor bol vytvorený. Aj keď medzitým nejaké iné vlákno pridá alebo odstráni prvok zo zoznamu, táto úprava vytvorí novú kópiu údajov, ktorá sa použije pri ďalšom vyhľadávaní údajov zo zoznamu.

Vďaka charakteristikám tejto dátovej štruktúry je obzvlášť užitočná v prípadoch, keď ju iterujeme častejšie, ako ju upravujeme. Ak je v našom scenári pridávanie prvkov bežnou operáciou, potom CopyOnWriteArrayList nebude dobrá voľba - pretože ďalšie kópie určite povedú k nižšiemu výkonu.

3. Iterácia CopyOnWriteArrayList Pri vkladaní

Povedzme, že vytvárame inštanciu súboru CopyOnWriteArrayList ktoré ukladajú celé čísla:

CopyOnWriteArrayList numbers = new CopyOnWriteArrayList (new Integer [] {1, 3, 5, 8});

Ďalej chceme iterovať cez toto pole, takže vytvárame Iterátor inštancia:

Iterátor iterátor = numbers.iterator ();

Po Iterátor je vytvorený, pridávame do prvku nový prvok čísla zoznam:

čísla.pridat (10);

Majte na pamäti, že keď vytvoríme iterátor pre CopyOnWriteArrayList, získame nemennú snímku údajov v danom čase iterátor () bol volaný.

Z tohto dôvodu sa pri iterácii toho čísla nedočkáme 10 v iterácii:

Výsledok zoznamu = new LinkedList (); iterator.forEachRemaining (result :: add); tvrdiťTo (výsledok). obsahuje Iba (1, 3, 5, 8);

Následná iterácia pomocou novovytvoreného Iterátor vráti aj číslo 10, ktoré bolo pridané:

Iterátor iterátor2 = numbers.iterator (); Zoznam výsledok2 = nový LinkedList (); iterator2.forEachRemaining (result2 :: add); tvrdiťTo (výsledok2) .obsahuje Iba (1, 3, 5, 8, 10);

4. Odstraňovanie počas iterácie nie je povolené

The CopyOnWriteArrayList bol vytvorený s cieľom umožniť bezpečnú iteráciu prvkov, aj keď dôjde k úprave základného zoznamu.

Z dôvodu kopírovacieho mechanizmu odstrániť () operácia na vrátenom Iterátor nie je povolené - výsledkom je UnsupportedOperationException:

@Test (očakáva sa = UnsupportedOperationException.class) public void whenIterateOverItAnd TryToRemoveElement_thenShouldThrowException () {CopyOnWriteArrayList numbers = new CopyOnWriteArrayList (new Integer [] {1, 3, 5, 8}); Iterátor iterátor = numbers.iterator (); while (iterator.hasNext ()) {iterator.remove (); }}

5. Záver

V tomto rýchlom výučbe sme sa pozreli na CopyOnWriteArrayList implementácia z java.util.concurrent balíček.

Videli sme zaujímavú sémantiku tohto zoznamu a to, ako je možné ho iterovať spôsobom bezpečným pre vlákna, zatiaľ čo iné vlákna môžu pokračovať vo vkladaní alebo odstraňovaní prvkov z neho.

Implementáciu všetkých týchto príkladov a útržkov kódu nájdete v projekte GitHub - jedná sa o projekt Maven, takže by malo byť ľahké ho importovať a spustiť tak, ako je.


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