【发布时间】:2012-01-10 08:29:31
【问题描述】:
我想讨论一下我对并发映射的特定用途,以检测我的逻辑......
如果我用ConcurrentHashMap,我可以做熟悉的
private final ConcurrentHashMap<K, V> map = new ConcurrentHashMap<K, V>();
public V getExampleOne(K key) {
map.putIfAbsent(key, new Object());
return map.get(key);
}
但我意识到存在竞争条件,如果我从putIfAbsent 和get 之间的映射中删除该项目,上述方法将返回不再存在于收藏。这可能好也可能不好,但让我们假设对于我的用例来说,这不好。
我真正想要的是让整个事情都原子化。所以,
public V getExampleTwo(K key) {
return map.putIfAbsent(key, new Object());
}
但是随着这扩展到
if (!map.containsKey(key))
return map.put(key, value); [1]
return map.get(key);
第 [1] 行第一次使用时将返回 null(即,map.put 将返回前一个值,第一次使用时为 null)。
在这种情况下我不能让它返回 null
这给我留下了类似的东西;
public V getExampleThree(K key) {
Object object = new Object();
V value = locks.putIfAbsent(key, object);
if (value == null)
return object;
return value;
}
所以,最后,我的问题;上面的例子在语义上有何不同? getExampleThree 是否确保像 getExampleTwo 一样的原子性但正确避免 null 返回? getExampleThree 还有其他问题吗?
我希望围绕这些选择进行一些讨论。我意识到我可以使用非ConcurrentHashMap 并围绕调用我的get 方法的客户端和从地图中删除的方法进行同步,但这似乎违背了ConcurrentHashMap 的目的(非阻塞性质)。 这是我保持数据准确的唯一选择吗?
我想这也是您选择 ConcurrentHashMap 的部分原因;在您与之交互时它是可见的/最新的/准确的,但是如果旧数据将成为问题,则可能会进一步产生影响...
【问题讨论】:
-
你允许空值作为值吗?如果是,那么 getExampleThree 中的值为 null 并不一定意味着没有与该键相关的内容。
-
此外,如果您介意示例 1 中的竞速条件,则示例 3 中存在竞速条件(当您的方法返回值/对象时,它可能不再在映射中)。
-
从不添加Null值,只是在getExample2中可以返回null
标签: java multithreading concurrency concurrenthashmap