confurnthashmap和fibonacci数字 - 结果不一致



我用ConcurrentHashMapcomputeIfAbsent()方法递归地编写了一个用于递归计算数字的程序:

当我使用诸如 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 ..但不是。

相关内容

  • 没有找到相关文章

最新更新