web-dev-qa-db-fra.com

Comment CopyWriRearrayList peut-il être le fil-faire?

J'ai pris un oeil sur code source OpenJDK de CopyOnWriteArrayList et il semble que toutes les opérations d'écriture soient protégées par les mêmes opérations de verrouillage et de lecture ne sont pas protégées. du tout. Si je comprends bien, sous JMM, tous les accès à une variable (à la fois lire et écrire) doivent être protégés par des effets de verrouillage ou de réorganisation.

Par exemple, set(int, E) méthode contient ces lignes (sous serrure):

/* 1 */ int len = elements.length;
/* 2 */ Object[] newElements = Arrays.copyOf(elements, len);
/* 3 */ newElements[index] = element;
/* 4 */ setArray(newElements);

La méthode get(int), d'autre part, seulement return get(getArray(), index);.

Dans ma compréhension de JMM, cela signifie que get peut observer la matrice dans un état incohérent si les déclarations 1 à 4 sont réorganisées comme 1-2 (nouveau) -4-2 (copie) -3.

Est-ce que je comprends mal JMM ou y a-t-il d'autres explications sur la raison pour laquelle CopyOnWriteArrayList est le fil-faire?

56
Fixpoint

Si vous regardez la référence de matrice sous-jacente, vous verrez qu'il est marqué comme volatile. Lorsqu'une opération d'écriture survient (telle que dans l'extrait ci-dessus), cette référence volatile est uniquement mise à jour dans la déclaration finale via setArray. Jusqu'à ce point, toutes les opérations de lecture renvoient des éléments de l'ancienne copie de la matrice.

Le point important est que la mise à jour de la matrice est une opération atomique et les lectures verront donc toujours la matrice dans un état cohérent.

L'avantage de la prise d'un verrouillage des opérations d'écriture est un débit amélioré pour les lectures: c'est parce que les opérations d'écriture pour un CopyOnWriteArrayList peuvent potentiellement être très lentes car elles impliquent la copie de la liste complète.

68
Adamski

Obtenir la référence de la matrice est une opération atomique. Ainsi, les lecteurs verront l'ancien tableau ou le nouveau tableau - de toute façon l'état est cohérent. (set(int,E) calcule le contenu de la nouvelle matrice avant de définir la référence. La matrice est donc cohérente lorsque la similitude est faite.)

La référence de matrice elle-même est marquée comme volatile afin que les lecteurs n'ont pas besoin d'utiliser un verrou pour voir les modifications apportées à la matrice référencée. (Edit: En outre, volatile _ garantit que la cession n'est pas ré-ordonnée, ce qui entraînerait la cession lorsque le tableau est éventuellement dans un état incohérent.)

Le verrouillage de l'écriture est requis pour empêcher la modification simultanée, ce qui peut entraîner la perte de données incohérentes ou des changements inconsistants.

18
mdma