Panduan untuk CopyOnWriteArrayList

1. Gambaran keseluruhan

Dalam artikel ringkas ini, kita akan melihat CopyOnWriteArrayList dari pakej java.util.concurrent .

Ini adalah konstruk yang sangat berguna dalam program multi-utas - apabila kita mahu melakukan lelaran ke atas senarai dengan cara yang selamat untuk benang tanpa penyegerakan yang jelas.

2. CopyOnWriteArrayList API

Reka bentuk CopyOnWriteArrayList menggunakan teknik yang menarik untuk menjadikannya selamat dalam benang tanpa memerlukan penyegerakan. Apabila kita menggunakan salah satu kaedah ubah suai - seperti menambah () atau membuang () - keseluruhan kandungan CopyOnWriteArrayList disalin ke salinan dalaman yang baru.

Oleh kerana fakta sederhana ini, kami dapat melakukan lelaran ke atas senarai dengan cara yang selamat, walaupun berlaku pengubahsuaian bersamaan .

Semasa kami memanggil kaedah iterator () pada CopyOnWriteArrayList, kami mendapat Iterator yang disokong oleh snapshot yang tidak berubah dari kandungan CopyOnWriteArrayList .

Kandungannya adalah salinan data yang tepat yang terdapat di dalam ArrayList sejak masa Iterator dibuat. Walaupun sementara itu beberapa utas lain menambah atau membuang elemen dari daftar, pengubahsuaian itu membuat salinan baru data yang akan digunakan dalam pencarian data lebih lanjut dari daftar itu.

Ciri-ciri struktur data ini menjadikannya sangat berguna dalam kes-kes ketika kita berulang kali lebih kerap daripada kita mengubahnya. Sekiranya menambahkan elemen adalah operasi biasa dalam senario kami, maka CopyOnWriteArrayList tidak akan menjadi pilihan yang baik - kerana salinan tambahan pasti akan membawa kepada prestasi di bawah par.

3. Pengulangan Lebih dari CopyOnWriteArrayList Semasa Memasukkan

Katakan bahawa kita membuat contoh CopyOnWriteArrayList yang menyimpan bilangan bulat:

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

Seterusnya, kami ingin melakukan iterasi pada array itu, jadi kami membuat contoh Iterator :

Iterator iterator = numbers.iterator();

Setelah Iterator dibuat, kami menambahkan elemen baru ke senarai nombor :

numbers.add(10);

Perlu diingat bahawa, ketika kita membuat iterator untuk CopyOnWriteArrayList, kita mendapat snapshot data yang tidak berubah dalam senarai pada waktu iterator () dipanggil.

Oleh kerana itu, semasa mengulanginya, kita tidak akan melihat nombor 10 dalam lelaran:

List result = new LinkedList(); iterator.forEachRemaining(result::add); assertThat(result).containsOnly(1, 3, 5, 8);

Pengulangan selanjutnya menggunakan Iterator yang baru dibuat juga akan mengembalikan nombor 10 yang ditambahkan:

Iterator iterator2 = numbers.iterator(); List result2 = new LinkedList(); iterator2.forEachRemaining(result2::add); assertThat(result2).containsOnly(1, 3, 5, 8, 10);

4. Mengeluarkan Semasa Menguling Tidak Dibolehkan

The CopyOnWriteArrayList telah dicipta untuk membolehkan kemungkinan mengulanginya selamat ke atas unsur-unsur walaupun senarai yang mendasari mendapat diubahsuai.

Kerana mekanisme penyalinan, operasi hapus () pada Iterator yang dikembalikan tidak dibenarkan - dihasilkan dengan UnsupportedOperationException:

@Test(expected = UnsupportedOperationException.class) public void whenIterateOverItAndTryToRemoveElement_thenShouldThrowException() { CopyOnWriteArrayList numbers = new CopyOnWriteArrayList(new Integer[]{1, 3, 5, 8}); Iterator iterator = numbers.iterator(); while (iterator.hasNext()) { iterator.remove(); } }

5. Kesimpulan

Dalam tutorial ringkas ini, kami melihat pelaksanaan CopyOnWriteArrayList dari pakej java.util.concurrent .

Kami melihat semantik menarik dari senarai ini dan bagaimana ia dapat dilakukan secara selamat dengan benang yang selamat, sementara utas lain dapat terus memasukkan atau mengeluarkan unsur daripadanya.

Pelaksanaan semua contoh dan coretan kod ini terdapat dalam projek GitHub - ini adalah projek Maven, jadi mudah untuk diimport dan dijalankan sebagaimana adanya.