Vous aimez ce que vous lisez sur ce blog ?
Envie d'aller plus loin avec véritable formation d'expertise en Java ?
Venez suivre ma formation Masterclasse Expertise Java !

"Même un développeur experimenté a besoin de continuer à apprendre. Et dans cette formation... j'ai appris beaucoup !" - A.G., Java Champion

Prochaines sessions inter-entreprises : 28-31 mars 2017 / 13-16 juin 2017
Sessions intra-entreprises sur demande.
Inscrivez-vous vite !

CopyOnWriteArrayList concurrency fun : un billet d'Alex Miller

Alex Miller a publié aujourd'hui un article intéressant sur le fonctionnement interne de la classe CopyOnWriteArrayList.
En voici une traduction rapide.

J'ai déjà mentionné la classe CopyOnWriteArrayList dans un billet précédent de la série "bugs relatifs aux accès concurrents". Il se trouve que j'ai eu besoin de regarder son code source aujourd'hui, et il apparaît qu'elle repose sur une architecture concurrente remarquable mais pas forcément évidente à comprendre.

Quelques patterns intéressants garantissent que les accès en lecture et en écriture sont bien sécurisés. Tout repose sur le fait que les données sont stockées en interne dans un tableau déclaré volatile, dont les éléments sont immuables. Nous allons le voir, ces deux propriétés (la volatilité du tableau et l'immuabilité des données) sont très importantes.

Les lectures de la liste ne requièrent aucune synchronisation ; c'est la volatilité du tableau interne qui garantit que les lecteurs verront toujours les dernières modifications en date. Mais, comme vous le savez (ou non), le fait qu'un tableau soit volatile ne signifie pas que ses éléments le soient (ceci pourrait d'ailleurs faire l'objet d'un prochain billet sur les bugs relatifs aux accès concurrents). De ce fait, la modification d'un élément du tableau ne serait pas nécessairement immédiatement visible aux lecteurs. Mais comme les éléments du tableau sont immuables, le problème ne se pose pas. Voilà pour la lecture.

Pour l'écriture, le problème est différent. Afin de sécuriser les écritures simultanées, toutes les méthodes de modification sont synchronisées (comme dans Vector). En interne, la modification est effectuée en créant une copie de la liste originale, en la modifiant, puis en remplaçant le tableau volatile interne par la version modifiée. La synchronisation protège ainsi des accès concurrents en écriture, et la volatilité du tableau garantit que la nouvelle valeur sera immédiatement visible aux lecteurs, de manière prédictible.

Les itérateurs, quant à eux, sont supposés toujours voir l'ancienne version de la liste, comment est-ce possible ? Tout simplement parce que l'itérateur reçoit lors de sa création une référence sur le tableau interne valide à cet instant[1]. Et comme cette référence n'est jamais modifiée, il continue à parcourir ce même tableau, même si la liste le remplace par une version modifiée.

Beau travail.

Notes

[1] Javadoc : The "snapshot" style iterator method uses a reference to the state of the array at the point that the iterator was created. This array never changes during the lifetime of the iterator, so interference is impossible and the iterator is guaranteed not to throw ConcurrentModificationException. The iterator will not reflect additions, removals, or changes to the list since the iterator was created. Element-changing operations on iterators themselves (remove, set, and add) are not supported. These methods throw UnsupportedOperationException.


Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.