Java8:ConcurrentHashMap.compute原子性
我正在尝试使用ConcurrentHashMap.compute实现一些东西,但我无法确定我的逻辑是否100%线程安全且正确。Java8:ConcurrentHashMap.compute原子性,java,concurrency,java-8,Java,Concurrency,Java 8,我正在尝试使用ConcurrentHashMap.compute实现一些东西,但我无法确定我的逻辑是否100%线程安全且正确。 Javadoc说关于compute(K键,双功能是的,在ConcurrentHashMap的情况下,您有这个保证。只要这些副作用不包括对同一映射的其他操作。但是,强烈建议只对包含的值应用副作用,因为其他任何东西都很快将无法维护。关于您的示例,createEvent和threadPool.addEvent如果有人同时对不同的键执行相同的操作,则仍然可能会使用其他参数调用。
Javadoc说关于
compute(K键,双功能是的,在ConcurrentHashMap
的情况下,您有这个保证。只要这些副作用不包括对同一映射的其他操作。但是,强烈建议只对包含的值应用副作用,因为其他任何东西都很快将无法维护。关于您的示例,createEvent
和threadPool.addEvent如果有人同时对不同的键执行相同的操作,则仍然可能会使用其他参数调用。此外,为什么要复制updatemap.keySet()
在迭代之前将其复制到一个新的HashSet
中?如果有人同时为另一个键调用createEvent或threadPool.addEvent,则没有问题。我决定在迭代之前复制该键集,因为迭代器的一致性很弱,我希望避免为同一id在e同一次迭代(删除id+创建事件,有人再次添加该id并再次迭代)您需要从其id
访问更新
,即map.get(id)
?@Holger虽然你是对的,但我们有一个缺陷,即有人决定通过CHM::computeIfAbsent
延迟加载服务,同时也依赖于其他服务。简单地说,computeIfAbsent
不仅更新了它的键/值,而且还更新了地图上的其他一些内容-这将导致死锁…增加容量“提供”了一个非常大的值,这样就不会发生重新调整尺寸的情况,这是一个解决方案,我至今也不同意。因此,说到点子上:你说的任何话都算是一个答案。
final Set<UniqueID> updatedIds = new HashSet<>(updatesMap.keySet());
for (final ID id : updatedIds) {
updatesMap.compute(id, (modifiedId, updates) -> {
final Event event = createEvent(modifiedId, updates);
threadPool.addEvent(event);
return null;
});
}