我用ConcurrentHashMap
和computeIfAbsent()
方法递归地编写了一个用于递归计算数字的程序:
当我使用诸如 8,9,10
之类的小值时,程序绝对可以正常工作
public class Test {
static Map<Integer, Integer> concurrentMap = new ConcurrentHashMap<>();
public static void main(String[] args) {
System.out.println("Fibonacci result for 20 is" + fibonacci(20));
}
static int fibonacci(int i) {
if (i == 0)
return i;
if (i == 1)
return 1;
return concurrentMap.computeIfAbsent(i, (key) -> {
System.out.println("Value is " + key);
return fibonacci(i - 2) + fibonacci(i - 1);
});
}
}
有人可以告诉我为什么它永远卡住了吗?
您正在陷入僵局。
computeIfAbsent
concurrenthashmap上的 CC_5将锁定相应键将转到的存储桶。如果您试图计算一个高于地图中的存储桶数量的斐波那契,则递归调用将尝试锁定已经在呼叫堆栈上进一步锁定的存储桶。但是,当然,直到所有递归电话都完成后,该锁才能释放。因此,您的僵局。
我会重新考虑您在此处使用ConcurrentHashMap
的决定。
这种计算斐波那契数的递归方法是指数复杂性。通过缓存,您将其降低到线性,或者您可以使用简单的周期而不是递归来获得线性算法。
我想知道为什么您要使用ConturenthashMap进行缓存。我将使用简单的地图或数组进行缓存。
地图在数组中具有优势,当值稀少时,但是当您具有数字序列时,您可以使用简单的数组。
我进行了线程转储,我们可以看到锁定的线程 0x000000076b70bba0 正在引起死锁问题。
如果错了,请纠正我。
main - priority:5 - threadId:0x00000000021af000 - nativeId:0x2798 - state:RUNNABLE
stackTrace:
java.lang.Thread.State: RUNNABLE
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1674)
- locked <0x000000076b70bba0> (a java.util.concurrent.ConcurrentHashMap$ReservationNode)
at Test.fibonacci(Test.java:18)
at Test.lambda$0(Test.java:20)
at Test$$Lambda$1/834600351.apply(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
- locked <0x000000076b70c720> (a java.util.concurrent.ConcurrentHashMap$ReservationNode)
at Test.fibonacci(Test.java:18)
at Test.lambda$0(Test.java:20)
at Test$$Lambda$1/834600351.apply(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
- locked <0x000000076b70c5c0> (a java.util.concurrent.ConcurrentHashMap$ReservationNode)
at Test.fibonacci(Test.java:18)
at Test.lambda$0(Test.java:20)
at Test$$Lambda$1/834600351.apply(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
- locked <0x000000076b70c460> (a java.util.concurrent.ConcurrentHashMap$ReservationNode)
at Test.fibonacci(Test.java:18)
at Test.lambda$0(Test.java:20)
at Test$$Lambda$1/834600351.apply(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
- locked <0x000000076b70c300> (a java.util.concurrent.ConcurrentHashMap$ReservationNode)
at Test.fibonacci(Test.java:18)
at Test.lambda$0(Test.java:20)
at Test$$Lambda$1/834600351.apply(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
- locked <0x000000076b70c1a0> (a java.util.concurrent.ConcurrentHashMap$ReservationNode)
at Test.fibonacci(Test.java:18)
at Test.lambda$0(Test.java:20)
at Test$$Lambda$1/834600351.apply(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
- locked <0x000000076b70c040> (a java.util.concurrent.ConcurrentHashMap$ReservationNode)
at Test.fibonacci(Test.java:18)
at Test.lambda$0(Test.java:20)
at Test$$Lambda$1/834600351.apply(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
- locked <0x000000076b70bee0> (a java.util.concurrent.ConcurrentHashMap$ReservationNode)
at Test.fibonacci(Test.java:18)
at Test.lambda$0(Test.java:20)
at Test$$Lambda$1/834600351.apply(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
- locked <0x000000076b70bba0> (a java.util.concurrent.ConcurrentHashMap$ReservationNode)
at Test.fibonacci(Test.java:18)
at Test.main(Test.java:8)
Locked ownable synchronizers:
- None
根据Oracle Doc
在进行计算时,可能会阻止其他线程对此地图的一些尝试更新操作,因此计算应简短而简单,并且不得尝试更新此地图的任何其他映射
正如 joe c 在最高答案中所说的那样,ConcurrentHashMap
的默认初始化在实例化时分配了少量的存储桶。
使用ConcurrentHashMap
的目的是允许从多个线程同时修改地图,而无需阻止它们(链接(。
如果您仍然想留在应用程序中使用ConcurrentHashMap
,那么我建议在创建期间增加初始容量。
static Map<Integer, Integer> concurrentMap = new ConcurrentHashMap<>(11);
可以将fibonacci系列计算为最多,包括25
根据文档,
concurrenthashmap((
使用默认的初始表大小(16(创建一个新的空图。
但是,我希望在此方面有所不同,因为我注意到默认尺寸要小得多。
原因是当您从ConcurrentHashMap<>(11)
获得fibonacci(25)
,然后ConcurrentHashMap<>()
&lt; - 应该在此处默认16 ..但不是。