我在多线程环境中有一个有状态bean,它将其状态保持在一个映射中。现在,我需要一种方法,在一个原子操作中替换映射的所有值。
public final class StatefulBean {
private final Map<String, String> state = new ConcurrentSkipListMap<>();
public StatefulBean() {
//Initial state
this.state.put("a", "a1");
this.state.put("b", "b1");
this.state.put("c", "c1");
}
public void updateState() {
//Fake computation of new state
final Map<String, String> newState = new HashMap<>();
newState.put("b", "b1");
newState.put("c", "c2");
newState.put("d", "d1");
atomicallyUpdateState(newState);
/*Expected result
* a: removed
* b: unchanged
* C: replaced
* d: added*/
}
private void atomicallyUpdateState(final Map<String, String> newState) {
//???
}
}目前,我使用ConcurrentSkipListMap作为ConcurrentMap的实现,但这不是一个要求。
解决这个问题的唯一方法是制作全局state volatile,并完全替换映射或使用AtomicReferenceFieldUpdater。有更好的办法吗?
我的更新非常频繁,每秒钟更新一次或两次,但机会很少。此外,整个地图将只包含少于20个值。
发布于 2018-05-14 14:31:47
使用CAS和AtomicReference的方法是在每次大容量更新时复制地图内容。
AtomicReference<Map<String, String>> workingMapRef = new AtomicReference<>(new HashMap<>());这个映射可以是并发的,但是对于“批量更新”,它是只读的。然后在updateState中循环doUpdateState(),直到实现为止,这意味着您的值已经被更新。
void updateState() {
while (!doUpdateState());
}
boolean doUpdateState() {
Map<String, String> workingMap = workingMapRef.get();
//copy map content
Map<String, String> newState = new HashMap<>(workingMap); //you can make it concurrent
newState.put("b", "b1");
newState.put("c", "c2");
newState.put("d", "d1");
return workingMapRef.compareAndSet(workingMap, newState);
}发布于 2018-05-14 13:40:22
最简单、最简单的方法是切换地图,而不是替换地图内容。无论是使用volatile还是AtomicReference (我不明白为什么特别需要AtomicReferenceFieldUpdater ),都不会有太大的不同。
这确保您的地图始终处于正确的状态,并允许您提供快照。但是,它并不能保护您免受其他并发问题的影响,因此,如果丢失更新之类的问题,您将需要进一步的代码(尽管AtomicReference将为您提供处理这些问题的CAS方法)。
如果您只考虑地图的完全原子替换,问题实际上是相当简单的。了解哪些其他操作影响到地图,以及如何影响地图,这将是信息丰富的。我还想知道为什么选择ConcurrentSkipListMap而不是ConcurrentHashMap。
发布于 2018-05-14 13:10:14
扩展您选择的映射实现,并添加一个同步方法:
class MyReplaceMap<K, V> extends HashMap<K, V> //or whatever
{
public synchronized void replaceKeys(final Map<K, V> newMap)
{
//.. do some stuff
}
}当然,您总是可以使state非最终易失性,并重新分配它(assignment is atomic)。
private volatile Map<String, String> state = new HashMap<>();
//...
final Map<String, String> newState = new HashMap<>();
newState.put("b", "b1");
newState.put("c", "c2");
newState.put("d", "d1");
state = newState;https://stackoverflow.com/questions/50331066
复制相似问题