When I want to implement a^b efficiently, I used concurrent hashmap to store calculated value, and the code is
private static final ConcurrentHashMap<String,Long> cache = new ConcurrentHashMap();
public long pow(long a, long b){
System.out.printf("%d ^ %d%n",a,b);
if(b == 1L){
return a;
}
if( b == 2L){
return a*a;
}
long l = b/2;
long r = b - l;
return cache.computeIfAbsent(a+","+l,k->pow(a,l)) * cache.computeIfAbsent(a+","+r,k->pow(a,r));
}
then I call this method
pow(2, 30);
but after outputting
2 ^ 30
2 ^ 15
2 ^ 7
it is blocked , by using jstack -l pid
I got below info
"main" #1 prio=5 os_prio=31 tid=0x00007f910e801800 nid=0x1703 runnable [0x0000700000217000]
java.lang.Thread.State: RUNNABLE
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1718)
at interview.Pow.pow(Pow.java:28)
at interview.Pow.lambda$pow$0(Pow.java:28)
at interview.Pow$$Lambda$1/1807837413.apply(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
- locked <0x000000076b72d930> (a java.util.concurrent.ConcurrentHashMap$ReservationNode)
at interview.Pow.pow(Pow.java:28)
at interview.Pow.lambda$pow$0(Pow.java:28)
at interview.Pow$$Lambda$1/1807837413.apply(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
- locked <0x000000076b72d060> (a java.util.concurrent.ConcurrentHashMap$ReservationNode)
at interview.Pow.pow(Pow.java:28)
at interview.Pow.testPow(Pow.java:32)
At first I doubt maybe deadlock happened, then after tracing source code of ConcurrentHashmap
, I know actually it is dead loop.
When key is 2,3
, it has the same index 9
of key 2,15
, but fh
(fh = f.hash) is -3
, cannot meet
if (fh >= 0) {...}
So in this case, it cannot break the loop
for (Node<K,V>[] tab = table;;) {...}
and loop infinitely.
Is it a bug or designed this so deliberately?
As C-Otto already commented, you invoke a second computeIfAbsent()
from within the first computeIfabsent()
method call. The documentation for this method clearly 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.
So this is no bug in the ConcurrentHashMap
implementation but in your code.