简体   繁体   中英

How to update a Value in a ConcurrentHashMap threadsafe

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

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.

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);
    }

I would say you can use

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM