问题
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