3

I hit live lock condition in concurrent hashmap #computeIfAbsent when function used for computation invokes #computeIfAbsent on the same map.

Conceptually call invocation look like following

final Map<String, Boolean> map = new ConcurrentHashMap<>();
map.computeIfAbsent("k1", k1 -> map.computeIfAbsent("k2", k2 -> Boolean.TRUE));

(with around 3ms of cpu burnt between computes). Unfortunately I can't come up with good unit test for to reproduce problem consistently.

However

there is another live lock which might give some clue is present if computation function tries to remove key on which it's invoked:

 final Map<String, Boolean> map = new ConcurrentHashMap<>();
 map.computeIfAbsent("k", k -> map.remove("k"));

while 2nd example is rather convoluted use of concurrent hash map, it results in the same stacktrace as first live lock so might be helpful.

Any help will be highly appreciated!

Petro Semeniuk
  • 6,491
  • 6
  • 37
  • 62
  • [Better error handing](http://stackoverflow.com/questions/28840047/recursive-concurrenthashmap-computeifabsent-call-never-terminates-bug-or-fea/28845674#28845674) is in Doug's repository, but not yet in a JDK release. – Ben Manes Sep 21 '15 at 01:55

1 Answers1

4

Well the ConcurrentHashMap.computeIfAbsent documentation explicitly says:

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.

Emphasis mine. Internally computeIfAbsent synchronizes on the hash-table entry which contains your key. You may have unexpected locks when you modify another key which happens to fall into the same entry as being processed currently.

In general you should avoid such modifications. Unfortunately you did not provide enough context for your problem, so I cannot propose an alternative solution.

Tagir Valeev
  • 87,515
  • 18
  • 194
  • 305