【发布时间】:2017-05-16 12:16:06
【问题描述】:
当我想高效实现a^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的源码,才知道原来是死循环。
当key为2,3时,与key2,15具有相同的索引9,但fh(fh = f.hash)为-3,不能满足
if (fh >= 0) {...}
所以在这种情况下,它不能打破循环
for (Node<K,V>[] tab = table;;) {...}
然后无限循环。
是bug还是故意设计的?
【问题讨论】:
-
您在地图上运行
computeIfAbsent时递归调用pow。因此,您有两次尝试写入地图。