简体   繁体   中英

Java 8 ConcurrentHashMap per key wait() within compute()

I want to be able to release the lock of an atomic execution like compute() to wait for a condition, how can I do that?

(Edited) Is there something that is like wait() (wait for a condition) just for the current key within compute() of ConcurrentHashMap (or getAnd*() functions of AtomicReference ), but will actually release the lock in Java 8? I'm also fine with using a totally different API.

I know I can do what I want if I have a separate list of objects/locks for each key, and use a plain old synchronized block, but I am looking for a less clunky way.

Pseudocode to illustrate:

public class Test {
    ConcurrentHashMap<String, Integer> map;

    public void illustration(String key) {
        map.computeIfPresent(key, (k, v) -> {
            Integer new_v = v;
            if (!/* Condition on v */) {
                // Pretend this will release the lock held by compute()
                k.wait(timeout);
                new_v = map.get(k);
            }
            if (/* Same condition on new_v */) {
                return /* Result of operation on new_v */;
            } else
                throw new RuntimeException();
        });
    }
}

I want to be able to release the lock of an atomic execution like compute() to wait for a condition, how can I do that?

Your pseudo-code using wait() doesn't release the lock(s) on the map. It is a bad idea.

The compute function will be called while holding a lock on part of the map. As the javadoc states:

"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."

A wait() call implies the possibility that other threads using the map may be blocked for the duration of the wait.

I guess your idea of "something equivalent" is another way of waiting on the condition. That will have the same issues.


And your followup / modified question.

Is there something that is like wait() (wait for a condition) just for the current key within compute() of ConcurrentHashMap (or getAnd*() functions of AtomicReference ), but will actually release the lock in Java 8? I'm also fine with using a totally different API.

No there isn't. The only way to get the computeIfPresent call to release its lock(s) on parts of the map is to terminate the call; ie return from your compute method or throw an exception.

This is just the way that mutual exclusion locking works in Java ... and in other languages. (No matter how you ask the question, the fundamental problem is the same.)

I think you need to go with your "clunky" approach.


The other thing to consider is that k.wait(...) is only allowed if you are holding the primitive lock on k . But k appears to be a String . This is liable to be problematic unless your map keys have been canonicalized ; eg by interning them.

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