java - 下面这段代码存在并发陷阱???
PHP中文网
PHP中文网 2017-04-18 10:10:31
0
2
481

曾宪杰的《大型网站系统与Java中间件实践》第一章第1.2.2.3小节给出以下代码示例:

使用HashMap数据被进行统计;

public class TestClass
{
    private HashMap<String, Integer> map = new HashMap<>();
    
    public synchronized void add(String key)
    {
        Integer value = map.get(key);
        if(value == null)
        {
            map.put(key, 1);
        }
        else
        {
            map.put(key, value + 1);
        }
    } 
}

使用ConcurrentHashMap保存数据并进行统计;

public class TestClass
{
    private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
    
    public void add(String key)
    {
        Integer value = map.get(key);
        if(value == null)
        {
            map.put(key, 1);
        }
        else
        {
            map.put(key, value + 1);
        }
    } 
}

使用HashMap时,对add方法加锁,此时该方法是线程安全的,为何换为ConcurrentHashMap之后,原书中说存在并发陷阱???

PHP中文网
PHP中文网

认证高级PHP讲师

répondre à tous(2)
巴扎黑

Pourquoi devons-nous verrouiller la méthode add après être passé à ConcurrentHashMap ? ? ?

public void add(String key)
    {
        Integer value = map.get(key);
        if(value == null)
        {
            map.put(key, 1);
        }
        else
        {
            map.put(key, value + 1);
        }
    } 

Il n’est pas verrouillé.

MODIFIER :

Il existe effectivement des pièges à concurrence. Considérez cette situation :

  1. Le thread A exécute map.get(key);if(value == null) pour obtenir le résultat vrai, puis transmet le temps CPU.

  2. À ce moment-là, le thread B s'exécute également au même endroit, et le résultat est également vrai, car le thread A n'a pas encore exécuté map.put(key, 1) et le thread B a exécuté map.put (key, 1) , À ce moment, la carte a déjà la valeur de key.

  3. Le thread A obtient du temps CPU pour continuer l'exécution. Étant donné que le résultat du jugement précédent était vrai, le thread A est remis en place. Le résultat final est que les deux threads exécutent map.put(key, 1) une fois. À ce stade, la valeur de key est toujours 1, mais elle devrait en réalité être 2.

La raison pour laquelle ce problème existe est qu'une seule opération de ConcurrentHashMap est atomique, mais votre appel externe n'est pas atomique. map.get et map.put sont deux opérations indépendantes l'une de l'autre, donc si vous voulez vous assurer du thread. Pour des raisons de sécurité, vous devez toujours ajouter des verrous à votre code pour garantir l'atomicité des opérations get et put.

左手右手慢动作

ConcurrentHashMap garantit uniquement que ses données internes peuvent rester cohérentes dans des conditions concurrentes, ce que HashMap ne peut pas faire.

Mais la méthode add n'est pas thread-safe car il s'agit d'un Check-Then-Act ou Read-Modify-Write typique.

Vous pouvez réfléchir à cette question, si tous les champs d'une classe sont des classes thread-safe, alors si cette classe est thread-safe. La réponse est évidemment non.

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!