Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
369 views
in Technique[技术] by (71.8m points)

multithreading - Java ConcurrentHashMap multi-thead env

I am making code that will be used like cache in multi-thread env.(If there is value already computed, I will not recompute it) So, I wondering below code is thread-safe.

public static <K, V> V getCreate(ConcurrentHashMap<K, V> map, K key, Function<K, V> function) {
    V v = map.get(key);
    if (v == null) {
        return map.putIfAbsent(key, function.apply(key));
    } else {
        return v;
    }
}

I knew about computeIfAbsent but after read this question(Why ConcurrentHashMap::putIfAbsent is faster than ConcurrentHashMap::computeIfAbsent?) and benchmark in my local env, I am finding other way. This is core logic of my benchmarking. getOrCreate faster about 9 times.

Benchmark Mode Cnt Score Units
computeIfAbsent avgt 2 3790.730 ns/op
getCreate avgt 2 436.348 ns/op

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your code is thread-safe, but there is a possibility that the function will be called multiple times for the same value.

For example this race condition:

//thread 1
V v = map.get(key);
if (v == null) {

    // thread 2 comes in
    {
      V v = map.get(key);
      if (v == null) {
         return map.putIfAbsent(key, function.apply(key));
      } else {
          return v;
      }
    }

    // thread 1 continues
    return map.putIfAbsent(key, function.apply(key));
} else {
    return v;
}

In this case, both thread1 and thread2 will execute function.apply(key), but the putIfAbsent will make sure only the first value is used. If you use put instead of putIfAbsent with this race condition, the last value will be used.

If you use computeIfAbsent with this race condition, only the first value will be used, but function.apply(key) will not even be executed the second time.

BTW, your benchmark is not really representative.

  • You allways use different keys, so the case where the same key is used is not tested.
  • The benchmark is single-threaded as far as I can see, so all locks will be skipped.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...