首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java:如何原子地替换Map中的所有值?

Java:如何原子地替换Map中的所有值?
EN

Stack Overflow用户
提问于 2018-05-14 13:05:26
回答 6查看 2K关注 0票数 5

我在多线程环境中有一个有状态bean,它将其状态保持在一个映射中。现在,我需要一种方法,在一个原子操作中替换映射的所有值。

代码语言:javascript
复制
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个值。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2018-05-14 14:31:47

使用CAS和AtomicReference的方法是在每次大容量更新时复制地图内容。

代码语言:javascript
复制
AtomicReference<Map<String, String>> workingMapRef = new AtomicReference<>(new HashMap<>());

这个映射可以是并发的,但是对于“批量更新”,它是只读的。然后在updateState中循环doUpdateState(),直到实现为止,这意味着您的值已经被更新。

代码语言:javascript
复制
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);
}
票数 2
EN

Stack Overflow用户

发布于 2018-05-14 13:40:22

最简单、最简单的方法是切换地图,而不是替换地图内容。无论是使用volatile还是AtomicReference (我不明白为什么特别需要AtomicReferenceFieldUpdater ),都不会有太大的不同。

这确保您的地图始终处于正确的状态,并允许您提供快照。但是,它并不能保护您免受其他并发问题的影响,因此,如果丢失更新之类的问题,您将需要进一步的代码(尽管AtomicReference将为您提供处理这些问题的CAS方法)。

如果您只考虑地图的完全原子替换,问题实际上是相当简单的。了解哪些其他操作影响到地图,以及如何影响地图,这将是信息丰富的。我还想知道为什么选择ConcurrentSkipListMap而不是ConcurrentHashMap

票数 2
EN

Stack Overflow用户

发布于 2018-05-14 13:10:14

扩展您选择的映射实现,并添加一个同步方法:

代码语言:javascript
复制
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)。

代码语言:javascript
复制
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;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50331066

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档