Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:如何原子地替换映射中的所有值?_Java_Multithreading_Dictionary_Concurrency - Fatal编程技术网

Java:如何原子地替换映射中的所有值?

Java:如何原子地替换映射中的所有值?,java,multithreading,dictionary,concurrency,Java,Multithreading,Dictionary,Concurrency,我在多线程环境中有一个状态bean,它将其状态保存在映射中。现在我需要一种方法在一个原子操作中替换该映射的所有值 public final class StatefulBean { private final Map<String, String> state = new ConcurrentSkipListMap<>(); public StatefulBean() { //Initial state this.sta

我在多线程环境中有一个状态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) {
        //???
    }
}
public最终类StatefulBean{
私有最终映射状态=新ConcurrentSkipListMap();
publicstatefulbean(){
//初始状态
本.状态.put(“a”、“a1”);
本.州.put(“b”、“b1”);
本.状态.put(“c”、“c1”);
}
公共屋({
//新状态的伪计算
final Map newState=new HashMap();
newState.put(“b”、“b1”);
newState.put(“c”、“c2”);
新闻状态。付诸表决(“d”、“d1”);
原子级更新状态(newState);
/*预期结果
*a:删除
*b:不变
*C:更换
*d:补充*/
}
私有void atomicallyUpdateState(最终映射newState){
//???
}
}
目前,我使用
ConcurrentSkipListMap
作为
ConcurrentMap
的实现,但这不是一个要求

解决此问题的唯一方法是使全局
状态
不稳定
,并完全替换映射或使用
原子引用字段dupdater
。 有更好的办法吗


我的更新相当频繁,每秒一到两次,但机会值很少。此外,整个映射只包含少于20个值。

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

class MyReplaceMap<K, V> extends HashMap<K, V> //or whatever
{
    public synchronized void replaceKeys(final Map<K, V> newMap)
    {
        //.. do some stuff
    }
}

因为地图很小,所以在您访问地图的所有地方使用
synchronized
就足够了

private void atomicallyUpdateState(final Map<String, String> newState) {
    synchronized(state) {
        state.clear();
        state.putAll(newState);
    }
}
需要成为

String myStatevalue;
synchronized (state) {
    myStatevalue = state.get("myValue");
}

否则读取和更新将不同步,并导致竞争条件。

由于客户端代码维护对bean的引用而不是映射,因此替换值(即整个映射)似乎是最简单的解决方案

除非有任何显著的性能问题(尽管使用锁定可能会执行得更糟,而且不太可预测,除非映射图很大),否则我会在需要更高级的知识之前尝试


这是一个函数式程序员应该做的。

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

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

如果你只考虑地图的完全原子替换,这个问题其实很简单。了解其他哪些操作会影响地图以及如何影响地图,这将是有益的。我还想听听为什么选择了
ConcurrentSkipListMap
而不是
ConcurrentHashMap

的CAS方法,并在每次批量更新时复制地图内容

AtomicReference<Map<String, String>> workingMapRef = new AtomicReference<>(new HashMap<>());

使用
ReadWriteLock
有助于自动替换映射中的所有值

private static final ReadWriteLock LOCK = new ReentrantReadWriteLock();

private void atomicallyUpdateState(final Map<String, String> newState) {
    LOCK.writeLock().lock();
    try {
        state.clear();
        state.putAll(newState);
    } finally {
        LOCK.writeLock().unlock();
    }
}
private static final ReadWriteLock LOCK=new ReentrantReadWriteLock();
私有void atomicallyUpdateState(最终映射newState){
LOCK.writeLock().LOCK();
试一试{
state.clear();
state.putAll(newState);
}最后{
LOCK.writeLock().unlock();
}
}

用更新后的值构建一个新映射,然后以原子方式交换它是否更容易?我猜这取决于你的客户端代码是保留对map还是bean的引用?你需要
updateState
成为原子吗?@schaffe不,只有
atomicallyUpdateState
成为原子,你认为通过原子交换可以避免什么竞争条件?@brabster只有bean会被引用,地图本身将是完全私有的——构建和交换整个地图只更新几个值感觉有点不对。但也许我的感觉是错误的,替换是最好的方法。信不信由你,我们有这样一种情况,我们真的不能对函数链接做任何事情。。(说来话长),但简短的版本是
map.computeifassent(“a”,x->{returnmap.computeifassent(“a”,y->1);})CHM
的code>将失败,但对于other@Eugene我懂了。听起来很有趣。我认为OP想要阻止读取,直到整个地图被更新,所以如果有更新过程,阻止读取,直到更新发生,但这只是一个猜测
AtomicReference<Map<String, String>> workingMapRef = new AtomicReference<>(new HashMap<>());
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);
}
private static final ReadWriteLock LOCK = new ReentrantReadWriteLock();

private void atomicallyUpdateState(final Map<String, String> newState) {
    LOCK.writeLock().lock();
    try {
        state.clear();
        state.putAll(newState);
    } finally {
        LOCK.writeLock().unlock();
    }
}