我阅读了所有与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以不同方式完成吗?
答案 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行之间。