shm*_*sel 10 java multithreading concurrenthashmap
我想定期迭代一段ConcurrentHashMap时间删除条目,如下所示:
for (Iterator<Entry<Integer, Integer>> iter = map.entrySet().iterator(); iter.hasNext(); ) {
Entry<Integer, Integer> entry = iter.next();
// do something
iter.remove();
}
Run Code Online (Sandbox Code Playgroud)
问题是,在迭代时,另一个线程可能正在更新或修改值.如果发生这种情况,那些更新可能会永远丢失,因为我的线程只会在迭代时看到陈旧的值,但remove()会删除实时条目.
经过一番考虑,我想出了这个解决方法:
map.forEach((key, value) -> {
// delete if value is up to date, otherwise leave for next round
if (map.remove(key, value)) {
// do something
}
});
Run Code Online (Sandbox Code Playgroud)
这样做的一个问题是它不会捕获对未实现的可变值的修改equals()(例如AtomicInteger).是否有更好的方法可以安全删除并发修改?
您的解决方法有效,但存在一种潜在的情况。如果某些条目不断更新,则在更新结束之前,map.remove(key,value) 可能永远不会返回 true。
如果你使用JDK8这里是我的解决方案
for (Iterator<Entry<Integer, Integer>> iter = map.entrySet().iterator(); iter.hasNext(); ) {
Entry<Integer, Integer> entry = iter.next();
Map.compute(entry.getKey(), (k, v) -> f(v));
//do something for prevValue
}
....
private Integer prevValue;
private Integer f(Integer v){
prevValue = v;
return null;
}
Run Code Online (Sandbox Code Playgroud)
compute() 会将 f(v) 应用于该值,在我们的例子中将该值分配给全局变量并删除该条目。
根据Javadoc,它是原子的。
尝试计算指定键及其当前映射值的映射(如果没有当前映射,则为 null)。整个方法调用是原子执行的。当计算正在进行时,其他线程对此映射的某些尝试更新操作可能会被阻止,因此计算应该简短,并且不得尝试更新此映射的任何其他映射。