Java 8 也许我';我发现了concurrenthashmap的一个bug
当我想要有效地实现^b时,我使用并发hashmap来存储计算值,代码是Java 8 也许我';我发现了concurrenthashmap的一个bug,java-8,concurrenthashmap,Java 8,Concurrenthashmap,当我想要有效地实现^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(
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));
}
但是在输出之后
2 ^ 30
2 ^ 15
2 ^ 7
它被阻塞了,通过使用jstack-lpid
我得到了下面的信息
"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)
所以在这种情况下,它不能打破循环
for (Node<K,V>[] tab = table;;) {...}
for(Node[]tab=table;;){…}
无限循环
这是一个bug还是故意设计的?正如C-Otto已经评论的那样,您在第一个
computeIfAbsent()
方法调用中调用了第二个computeIfAbsent()
。明确规定:
在计算过程中,其他线程对此映射尝试的某些更新操作可能会被阻止,因此计算应该简短,并且不得尝试更新此映射的任何其他映射。
因此,这在
ConcurrentHashMap
实现中并不是错误,而是在代码中。在映射上运行ComputeFabSent
时递归调用pow
。因此,您有两次尝试写入映射。是的,ConcurrentHashMap只是为并发使用而设计的,而不是递归使用,因此如果知道没有并发操作,应该将其更改为使用普通HashMap。但在一些罕见的场景中,可能同时存在并发操作和递归操作。那么在这种情况下,我应该使用什么地图?Collections.synchronizedMap()?
if (fh >= 0) {...}
for (Node<K,V>[] tab = table;;) {...}