web-dev-qa-db-fra.com

Avons-nous besoin de rendre ConcurrentHashMap volatile?

Nous avons un ConcurrentHashMap partagé qui est lu et écrit par 2 threads.

class Test {

    ConcurrentHashMap map;

    read() {
        map.get(object);
    }

    write() {
        map.put(key, object);
    }
}

Avons-nous besoin de rendre la carte volatile afin que les écritures d'un thread soient vues par les threads de lecture dès que possible?

Est-il possible qu'un put à la carte dans un thread ne soit pas vu ou vu très tard par un autre thread? Même question pour HashMap.

37
user3739844

Si vous pouvez le faire final alors faites-le. Si vous ne pouvez pas le faire final alors oui vous devrez le faire volatile. volatile s'applique à l'affectation de champ et si ce n'est pas final alors il y a une possibilité (au moins selon le JMM) qu'une écriture du champ CHM par un thread ne soit pas visible par un autre thread . Pour réitérer, il s'agit de l'affectation du champ ConcurrentHashMap et non de l'utilisation du CHM.

Cela étant dit, vous devriez vraiment le faire final.

Avons-nous besoin de rendre la carte volatile afin que les écritures d'un thread soient vues par les threads de lecture dès que possible?

Si les écritures dont vous parlez sont effectuées en utilisant les méthodes de mutation du CHM lui-même (comme put ou remove), vous rendre le champ volatile n'a pas d'effet. Toutes les garanties de visibilité de la mémoire sont effectuées au sein du CHM.

Est-il possible qu'un put à la carte dans un thread ne soit pas vu ou vu très tard par un autre thread? Même question pour HashMap.

Pas pour ConcurrentHashMap. Si vous utilisez simultanément un HashMap ordinaire, ne le faites pas. Voir: http://mailinator.blogspot.com/2009/06/beautiful-race-condition.html

34
John Vint

volatile applique la sémantique qui se produit avant la lecture et l'écriture dans la variable correspondante.

Un champ peut être déclaré volatile, auquel cas le modèle de mémoire Java garantit que tous les threads voient une valeur cohérente pour la variable (§17.4).

Cela n'a rien à voir avec les objets référencés par la valeur de la variable. Donc, à moins que vous ne modifiiez la variable sur plusieurs threads, non, vous n'avez pas besoin de la faire volatile.

Comme l'indique javadoc , toutes les méthodes ConcurrentHashMap agissent comme des barrières mémoire,

Les récupérations reflètent les résultats des opérations de mise à jour les plus récemment terminées qui se sont déroulées. (Plus formellement, une opération de mise à jour pour une clé donnée porte une relation passe-avant avec toute récupération (non nulle) pour cette clé signalant la valeur mise à jour.

10

Non, non.

volatile signifie que la variable ne peut pas être mise en cache dans un registre et sera donc toujours "écrite" dans la mémoire. Cela signifie que le changement d'un thread vers une variable sera visible pour les autres threads.

Dans ce cas, la variable est un référence à une carte. Vous utilisez la même carte tout le temps, donc vous ne changez pas la référence - vous modifiez plutôt le contenu de cette carte. (C'est-à-dire que la Carte est mutable.) Cela signifie également que vous pouvez, et donc devez, faire la référence à la Carte final.

Le ConcurrentHashMap diffère du HashMap en ce que vous pouvez généralement le lire en toute sécurité et y écrire en même temps à partir de différents threads, sans verrouillage externe. Cependant, si vous voulez pouvoir faire confiance à la taille à un moment donné, effectuer des opérations de vérification puis d'écriture ou similaires, vous devez le concevoir vous-même.

4
Bex