How to update a Value in a ConcurrentHashMap threadsafe

送分小仙女□ 提交于 2020-07-10 07:06:47

问题


I need to update a value in a ConcurrentHashmap but I am not sure on how to do this thread safe.

The Hashmap is a ConcurrentHashMap and I need to get the instance of the custom class, perform some operations on it and then put the updated value back in.

Is there any way to combine this get-alter-put operation to something atomic?

Thanks in advance


回答1:


You can use ConcurrentHashMaps computeIfPresent https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#computeIfPresent-K-java.util.function.BiFunction-

But since computeIfPresent is a costly operation as its atomic and some update operations will be blocked by other threads during the computation of the BiFunction . You can preclude this with a read operation on concurrent hashmap which is pretty fast and if that returns not null , invoke computeIfPrsent

Below code gets the value of key "1" and adds 100 to it and puts in back to the map in a atomic way

ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
        map.put(1,100);
        Integer value = map.get(1);
        if (value != null)
            map.computeIfPresent(1, (key, oldValue) -> oldValue + 100);
    }



回答2:


A ConcurrentHashMap's computeIfPresent method is a possibility. From the javadocs: If the value for the specified key is present, attempts to compute a new mapping given the key and its current mapped value. The entire method invocation is performed atomically (expects that computation should be short and simple).

How does the method work, in general? Some example code:

Consider a Map<String, Integer> map with keys and values: {four=4, one=1, ten=10, two=2, three=3, five=5, eleven=11}

(1) updates the mapping with new value (note the lambda is a BiFunction returning a newly computed value):

map.computeIfPresent("ten", (k, v) -> new Integer(100));

(2) the function returns a null, the existing mapping is removed:

map.computeIfPresent("eleven", (k, v) -> null);

(3) the mapping is not added, as there is no existing mapping:

map.computeIfPresent("twenty", (k, v) -> new Integer(20));

EDIT:

Note on compute(): Using the same input map data (and method arguments), the compute method works similarly but for the case 3. Note the case 3 where new mappings can be added:

(3) a new mapping is added.




回答3:


I would say you can use

map.compute(key,  (k,v) -> {
                      if(k != null) {
                        return v+1;
                      } else {
                        return some_var;
                      }
                    });


来源:https://stackoverflow.com/questions/51376675/how-to-update-a-value-in-a-concurrenthashmap-threadsafe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!