Guide de CopyOnWriteArrayList

1. Vue d'ensemble

Dans cet article rapide, nous examinerons la CopyOnWriteArrayList du package java.util.concurrent .

C'est une construction très utile dans les programmes multi-threads - lorsque nous voulons parcourir une liste de manière thread-safe sans synchronisation explicite.

2. API CopyOnWriteArrayList

La conception de CopyOnWriteArrayList utilise une technique intéressante pour la rendre thread-safe sans nécessiter de synchronisation. Lorsque nous utilisons l'une des méthodes de modification - telles que add () ou remove () - tout le contenu de CopyOnWriteArrayList est copié dans la nouvelle copie interne.

En raison de ce simple fait, nous pouvons parcourir la liste de manière sûre, même en cas de modification simultanée .

Lorsque nous appelons la méthode iterator () sur CopyOnWriteArrayList, nous récupérons un Iterator sauvegardé par l'instantané immuable du contenu de CopyOnWriteArrayList .

Son contenu est une copie exacte des données qui se trouvent à l' intérieur d'une ArrayList à partir du moment où l' itérateur a été créé. Même si entre-temps un autre thread ajoute ou supprime un élément de la liste, cette modification fait une nouvelle copie des données qui seront utilisées dans toute recherche de données ultérieure dans cette liste.

Les caractéristiques de cette structure de données la rendent particulièrement utile dans les cas où nous l'itérons plus souvent que nous la modifions. Si l'ajout d'éléments est une opération courante dans notre scénario, alors CopyOnWriteArrayList ne sera pas un bon choix - car les copies supplémentaires conduiront certainement à des performances inférieures à la normale.

3. Itération sur CopyOnWriteArrayList lors de l' insertion

Disons que nous créons une instance de CopyOnWriteArrayList qui stocke des entiers:

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

Ensuite, nous voulons itérer sur ce tableau, nous créons donc une instance Iterator :

Iterator iterator = numbers.iterator();

Une fois l' itérateur créé, nous ajoutons un nouvel élément à la liste des nombres :

numbers.add(10);

Gardez à l'esprit que, lorsque nous créons un itérateur pour CopyOnWriteArrayList, nous obtenons un instantané immuable des données de la liste au moment où iterator () a été appelé.

Pour cette raison, en l'itérant, nous ne verrons pas le nombre 10 dans l'itération:

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

Une itération ultérieure utilisant Iterator nouvellement créé renverra également le numéro 10 qui a été ajouté:

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

4. La suppression pendant l'itération n'est pas autorisée

Le CopyOnWriteArrayList a été créé pour permettre la possibilité d'itérer en toute sécurité sur des éléments même lorsque la liste sous - jacente se modifie.

En raison du mécanisme de copie, l' opération remove () sur l' itérateur retourné n'est pas autorisée - résultant avec 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. Conclusion

Dans ce rapide tutoriel, nous avons examiné l' implémentation de CopyOnWriteArrayList à partir du package java.util.concurrent .

Nous avons vu la sémantique intéressante de cette liste et comment elle peut être itérée de manière thread-safe, tandis que d'autres threads peuvent continuer à y insérer ou à supprimer des éléments.

L'implémentation de tous ces exemples et extraits de code se trouve dans le projet GitHub - il s'agit d'un projet Maven, il devrait donc être facile à importer et à exécuter tel quel.