当我想有效地实现^ b时,我使用并发hashmap来存储计算值,代码是
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));
}
然后我称这个方法
pow(2, 30);
但输出后
2 ^ 30
2 ^ 15
2 ^ 7
它被阻止,使用jstack -l pid
我得到以下信息
"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)
起初我怀疑可能发生了死锁,然后在追踪ConcurrentHashmap
的源代码后,我知道它实际上是死循环。
当密钥为2,3
时,它与密钥9
具有相同的索引2,15
,但fh
(fh = f.hash)为-3
,无法满足< / p>
if (fh >= 0) {...}
所以在这种情况下,它无法打破循环
for (Node<K,V>[] tab = table;;) {...}
并无限循环。
是故障还是故意设计?
答案 0 :(得分:2)
正如C-Otto已经评论过,您在第一个computeIfAbsent()
方法调用中调用了第二个computeIfabsent()
。 The documentation for this method明确指出:
计算正在进行时,其他线程可能会阻止此地图上的某些尝试更新操作,因此计算应该简短,并且不得尝试更新此映射的任何其他映射。
所以这不是ConcurrentHashMap
实现中的错误,而是代码中的错误。