Vodič za CopyOnWriteArrayList

1. Pregled

U ovom ćemo kratkom članku pogledati CopyOnWriteArrayList od java.util.concurrent paket.

Ovo je vrlo korisna konstrukcija u programima s više niti - kada želimo itirirati popis na nit-siguran način bez izričite sinkronizacije.

2. CopyOnWriteArrayList API

Dizajn CopyOnWriteArrayList koristi zanimljivu tehniku ​​kako bi ga učinili sigurnim za konac bez potrebe za sinkronizacijom. Kada koristimo bilo koju od metoda modificiranja - kao što je dodati() ili ukloniti () - cjelokupni sadržaj CopyOnWriteArrayList se kopira u novu internu kopiju.

Zbog ove jednostavne činjenice, možemo prelistavati popis na siguran način, čak i kad se događa istodobna modifikacija.

Kad zovemo iterator () metoda na CopyOnWriteArrayList, vraćamo an Iterator potkrijepljen nepromjenjivom snimkom sadržaja CopyOnWriteArrayList.

Sadržaj je točna kopija podataka koji se nalaze u ArrayList iz vremena kada je Iterator kreiran je. Čak i ako u međuvremenu neka druga nit doda ili ukloni element sa popisa, ta izmjena čini novu kopiju podataka koji će se koristiti u bilo kojem daljnjem pretraživanju podataka s tog popisa.

Karakteristike ove strukture podataka čine je posebno korisnom u slučajevima kada je ponavljamo češće nego što je mijenjamo. Ako je dodavanje elemenata uobičajena operacija u našem scenariju, tada CopyOnWriteArrayList neće biti dobar izbor - jer će dodatne kopije definitivno dovesti do slabije izvedbe.

3. Iteriranje preko CopyOnWriteArrayList Tijekom umetanja

Recimo da stvaramo instancu CopyOnWriteArrayList koji pohranjuje cijele brojeve:

CopyOnWriteArrayList numbers = novi CopyOnWriteArrayList (novi cijeli broj [] {1, 3, 5, 8});

Dalje, želimo se iterirati preko tog niza, pa stvaramo Iterator primjer:

Iterator iterator = numbers.iterator ();

Nakon što Iterator je stvoren, dodajemo novi element u brojevi popis:

brojevi.add (10);

Imajte na umu da, kada kreiramo iterator za CopyOnWriteArrayList, dobivamo nepromjenjivu snimku podataka na popisu u to vrijeme iterator () bio pozvan.

Zbog toga, dok se ponavljamo, nećemo vidjeti broj 10 u iteraciji:

Rezultat popisa = novi LinkedList (); iterator.forEachRemaining (rezultat :: dodaj); assertThat (result) .containsOnly (1, 3, 5, 8);

Naknadna iteracija pomoću novostvorenog Iterator također će vratiti broj 10 koji je dodan:

Iterator iterator2 = numbers.iterator (); Popis rezultata2 = novi LinkedList (); iterator2.forEachRemaining (result2 :: add); assertThat (result2) .contentOnly (1, 3, 5, 8, 10);

4. Uklanjanje tijekom ponavljanja nije dopušteno

The CopyOnWriteArrayList stvoren je kako bi se omogućila mogućnost sigurnog ponavljanja elemenata čak i kada se temeljni popis promijeni.

Zbog mehanizma kopiranja, ukloniti() operacija na vraćenom Iterator nije dopušteno - rezultira s UnsupportedOperationException:

@Test (očekuje se = UnsupportedOperationException.class) javna praznina whenIterateOverItAndTryToRemoveElement_thenShouldThrowException () {CopyOnWriteArrayList numbers = new CopyOnWriteArrayList (new Integer [] {1, 3, 5, 8, 8, 1, 3, 5, 8, 8; Iterator iterator = numbers.iterator (); while (iterator.hasNext ()) {iterator.remove (); }}

5. Zaključak

U ovom smo brzom vodiču pogledali CopyOnWriteArrayList provedba iz java.util.concurrent paket.

Vidjeli smo zanimljivu semantiku ovog popisa i kako se može ponoviti na siguran način, dok ostale niti mogu nastaviti s umetanjem ili uklanjanjem elemenata s njega.

Provedbu svih ovih primjera i isječaka koda možete pronaći u projektu GitHub - ovo je Maven projekt, pa bi ga trebalo lako uvesti i pokrenuti kakav jest.