如何执行并发安全映射对象操作?

时间:2015-01-19 22:01:45

标签: java multithreading concurrency concurrenthashmap

我阅读了所有与Java ConcurrentHashMap用法相反的内容。我希望我的问题有助于澄清一些看似简单的事情(最新答案)。

我有这样的地图:

ConcurrentHashMap<Integer, ClassA> map = new ConcurrentHashMap<Integer, ClassA>()

我正在使用ConcurrentHashMap来保持put和get操作线程的安全。我的ClassA有一些Integer / String属性和一个字符串集合。

现在我想知道如何安全地更新我的映射对象。如果我想通过添加一个新的String来创建一个从我的地图更新对象的方法,我有类似的东西:

        synchronized(map)
        {
            Collection<String> strings = map.get(id).getStrings();
            if(!strings.contains(newString)) //strings can't be null
            {
                strings.add(newString);
            }
        }

此代码对并发读/写是否安全?可以通过使用Java API以不同方式完成吗?

2 个答案:

答案 0 :(得分:2)

你的答案中的内容并非完全线程安全。它取代了密钥id的值,而不管旧值是什么。如果那对你的实现没问题那么好,但replace(K key, V oldObj, V newObj)是理想的检查和设置(CAS)方法来替换ConcurrentMap中的现有值。

在您的特定用例中,您将执行以下操作

ClassA oldObj = map.get(id);
ClassA newObject = new ClassA(oldObject, newValue);
return map.replace(id, oldObj, newObject);

这确保仅在前一个值为oldObj时才更新地图。如果此代码块由具有不同newValue的不同线程调用,会发生什么?上面的代码只会让一个线程成功,另一个线程会返回false。

答案 1 :(得分:0)

这是试图回答我自己的问题。我发现了另一个问题答案:What is the preferred way to modify a value in ConcurrentHashMap?

如果我使ClassA成为不可变的,并替换我的代码以更新我的地图对象:

        ClassA oldObject = map.get(id);
        ClassA newObject = new ClassA(oldObject, newValue);//this constructor copies the old one and add the newValue in my Collection of Strings
        map.put(id, newEvent);

它是线程安全的吗?我真的希望使用ConcurrentHashMap保持我的代码清洁和高效,我相信这个解决方案正朝着同一个方向发展。 我只是稍微怀疑任何线程检索同一个对象,而另一个线程将在第2行和第3行之间。