简体   繁体   中英

Does Java ConcurrentHashMap computeIfAbsent() method support key-based “locking”?

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#computeIfAbsent-K-java.util.function.Function-

Assume we have 10 threads calling the following codes with different key value. does the "Function" argument provided to the computeIfAbsent method run in parallel, or computeIfAbsent will "lock" the entire table?

Map<String, String> map = new ConcurrentHashMap<>();
map.computeIfAbsent(key, K -> { // long time operation });

There are two ways to interpret the question.

The first is, theoretically, does the specification of the ConcurrentHashMap.computeIfAbsent method guarantee to synchronize only on the particular key being computed? The answer to this comes straight from the documentation for the method :

Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map.

This is ambiguous on whether it synchronizes on the whole map or just the individual key, but it doesn't explicitly promise that updates on other keys can proceed in other threads while value-if-absent is being computed. It says "some attempted update operations" may be blocked, but doesn't impose a limit on which or how many are blocked. So the strict answer is, no , a conforming implementation is permitted to synchronize on the whole map object, and block all other updates.


The second interpretation of the question is, practically, does the implementation of the method synchronize on just the individual key? The answer to this will depend on which implementation, but will come from the source code of that implementation.

From the OpenJDK 8 implementation :

Node<K,V> f;
// ...
if(/* ... */) {
    // ...
} /* ... */ else if(/* ... */) {
    Node<K,V> r = new ReservationNode<K,V>();
    synchronized (r) {
        // ...
    }
    // ...
} /* ... */ else {
    // ...
    synchronized (f) {
        // ...
    }
    // ...
}

So the answer (at least if you're using this implementation) is yes , in practice the method synchronizes on an object (either f or r ) representing an individual key/value pair, not the whole map, so updates to other keys should not be blocked while the function is computed.

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