java - 多线程并发情况下Map.containsKey() 判断有问题
黄舟
黄舟 2017-04-18 10:49:53
0
3
1136

有下面一段代码:

package test;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class TestContain extends Thread{

       private final String key = "key";
    
       private final static ConcurrentMap<String, Object> locks = new ConcurrentHashMap<>();
        
        private static Object getLock(String lockName) {
            if (!locks.containsKey(lockName)) {
                //这一句会存在并发问题
                locks.put(lockName, new String("我是值"));
                System.out.println("加了一次");
            }
            return locks.get(lockName);
        }
        
        @Override
        public void run() {
            getLock(this.key);
        };
        
        public static void main(String[] args) {
            for (int i = 0; i < 20; i++) {
                new TestContain().start();;
            }
        }
}

输出结果:

加了一次
加了一次
加了一次

表明了Map.containsKey() 在多线程的情况下会判断不准确。

这是为什么呢? 有什么方法改进呢?

黄舟
黄舟

人生最曼妙的风景,竟是内心的淡定与从容!

répondre à tous(3)
PHPzhong

Le document de

ConcurrentHashMap contient un paragraphe

Les opérations de récupération (y compris <tt>get</tt>) ne bloquent généralement pas
et peuvent donc chevaucher les opérations de mise à jour (y compris

<tt>put</tt> et <tt>remove</tt>). Les récupérations reflètent les résultats
des opérations de mise à jour terminées les plus récemment
début.

La méthode get à l'intérieur ne se verrouille pas. La méthode get obtient uniquement la valeur de la dernière mise à jour terminée.

Ainsi, le locks.containsKey(lockName) dans la méthode sujet n'a pas de verrou pour garantir la sécurité des threads. Et il semble que le scénario d'utilisation de ConcurrentHashMap ne consiste pas à utiliser containsKey pour garantir que l'opération de mise à jour n'est effectuée qu'une seule fois, mais à utiliser putIfAbsent pour garantir.

小葫芦

ConcurrentMap garantit l'atomicité d'une seule opération, et non de plusieurs opérations.

Votre fonction getLock contient plusieurs opérations. ConcurrentMap ne peut pas étendre sa plage de synchronisation. Vous devez implémenter le verrou getLock vous-même.

迷茫

Utilisez la méthode putIfAbsent.

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!