在Java中的ConcurrentHashMap中以原子方式写入后,我们能否实现对可变数据的读取?

mit*_*shi 12 java concurrenthashmap

我正在尝试找到这些答案,但无法在Google或Java文档中理解(或确认)它.

我的实现看起来像这样:

Map<String, POJO> map = new ConcurrentHashMap<String, POJO>();
Run Code Online (Sandbox Code Playgroud)

如果我做

value1 = map.get(key1);
value1.setProp(prop);
Run Code Online (Sandbox Code Playgroud)

任何其他线程可能会覆盖.

现在,我在想如果我喜欢以下内容:它会是一个原子操作/换句话说,它会阻止key1段吗?

map.compute(key1, (key1, value1) -> { value1.setProp(prop) });
Run Code Online (Sandbox Code Playgroud)

Javadoc的compute功能

尝试计算指定键及其当前映射值的映射(如果没有当前映射,则为null).整个方法调用以原子方式执行.其他线程在此映射上的某些尝试更新操作可能在计算进行时被阻止,因此计算应该简短,并且不得尝试更新此Map的任何其他映射.

参考文献:

1. https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html 2. https://docs.oracle.com/javase/8/docs/api/java /util/concurrent/ConcurrentHashMap.html#compute-K-java.util.function.BiFunction-

编辑:

对于我的最终实现,我做了类似这样的事情,因为所有线程共享NewMap,最后,我新的POJO列表
抽象数据类型

    public class NewMap {

        private Map<String, POJO> map;
        private boolean isUpdatable;
        void NewMap(){
              isUpdatable = true;
              map = new ConcurrentHashMap();
        }

        void putPOJOProp1(String key, Type value) throws ReadOnlyException{

                  map.compute(key, (k,v) -> {
                           if(!isUpdatable) throw new ReadOnlyException();
                           if(k == null){ 
                              POJO p = new POJO();
                              p.setProp1(value);
                              v = p;
                           } else { 
                              v = v.setProp1(v)
                           }
             });
        }

        void putPOJOProp2....
        void putPOJOProp3....

        List<POJO> getAll() {
             isUpdatable = false;
             List<POJO> pojos;
             for(key: map.getKeys()) {
                  Pojo p = map.get(key);
                  p.setKey(key);
                  pojos.add(p);
             }
             return pojos;
        }
    }
Run Code Online (Sandbox Code Playgroud)

Ale*_*hin 8

你困惑的两个不同的术语.
ConcurrentHashMap防止内部结构腐败,但不防止竞争条件.如果你想避免的只是数据损坏,那么使用ConcurrentHashMap是有效的.
但是从你的问题看来,你似乎在试图避免竞争条件.ConcurrentHashMap不以任何方式保护你免受他们的伤害.

为了更好地理解它,让我们看看以下示例:

    Map<String, POJO> map = new ConcurrentHashMap<>();
    ExecutorService pool = Executors.newWorkStealingPool(10);

    for (int t = 0; t < 10; t++) {
        pool.execute(() -> {
            for (int i = 0; i < 100_000; i++) {
                map.compute("A", (k, v) -> {
                    if (v == null) {
                        return new POJO();
                    }
                    v.a = ++v.a;
                    v.b = ++v.b;

                    return v;
                });
            }
        });
    }

    pool.awaitTermination(5, TimeUnit.SECONDS);

    System.out.println(map);

    // With POJO like 
    class POJO {
       // toString() here
       Integer a = 1;
       Integer b = 1;
    }
Run Code Online (Sandbox Code Playgroud)

我们得到了{A=POJO{a=1000000, b=1000000}},所以我们的操作是线程安全的.如果这就是你想要的,你就没事了.


Pet*_*rey 8

ConcurrentHashMap.compute的Javadoc 说明

整个方法调用以原子方式执行.

注意,通过比较,ConcurrentSkipListMap.compute它不是原子的.

更为紧凑的Alexey Soshin的答案是

Map<String, long[]> map = new ConcurrentSkipListMap<>();
map.put("A", new long[2]);
IntStream.range(0, 1_000_000)
        .parallel()
        .forEach(i -> map.compute("A", (k, v) -> {
            v[0]++;
            v[1]++;
            return v;
        }));
System.out.println(Arrays.toString(map.get("A")));
Run Code Online (Sandbox Code Playgroud)

打印像

[643553, 597254]
Run Code Online (Sandbox Code Playgroud)

cf HashMap产生类似的东西

[244786, 245993]
Run Code Online (Sandbox Code Playgroud)

但是,使用a ConcurrentHashMap并获得预期

[1000000, 1000000]
Run Code Online (Sandbox Code Playgroud)