为什么我的 concurrentSkipListSet 在 multi add 时卡住了?

Why my concurrentSkipListSet stucks while multi add?

我想测试一下 ConcurrentSkipListSet 和 ConcurrentLinkedQueue 的性能,所以我做了一个测试:

ConcurrentSkipListSet<Integer> concurrentSkipListSet=new ConcurrentSkipListSet<>((o1,o2)->{return 1;});
HashSet<Callable<Integer>> sets=new HashSet<>();
for(int i=0;i<1000;i++){
    final int j=i;
    sets.add(()->{concurrentSkipListSet.add(j);
        System.out.println(j);
            return null;
    });
}
Long c=System.currentTimeMillis();
System.out.println(c);
ExecutorService service=Executors.newFixedThreadPool(10);
try {
    service.invokeAll(sets);
}catch(Exception e){}
System.out.println(System.currentTimeMillis()-c);

我很困惑,程序在 sout 大约 20~50 j 后卡住,大约一个小时内不会完成。如果我将 i 更改为 i<10,它有时会以 3 毫秒完成,或者有时会在 sout 后卡住大约 4~5 j。

一个newCachedThreadPool,与IDEA和Eclipse中的newFixedThreadPool一样。

请帮我分析一下,3Q。

现在我认为这不是 newCachedThreadPool 的问题,而是 concurrentSkipListSet.add(j); 当我将 SkipList 更改为 LinkedQueue 或同步的 HashSet 时,它运行良好并在 168 毫秒或 170 毫秒内完成。

请帮我分析一下,3Q。

问题可能出在您提供给 ConcurrentSkipListSet 构造函数的比较器中。它总是 returning 1 这可能会导致 ConcurrentSkipListSet 实现中的某种无限循环。您可以使用不带参数的 ConcurrentSkipListSet 构造函数来对 Integer.

使用自然排序

考虑一下当您总是从比较器 returning 1 时发生了什么:

假设我们有两个对象 A 和 B。排序算法在某个时候可能会要求您的比较器 "is A greater then B?" 调用 compare(A, B)。你 return 1 这意味着确实 A > B 并且 B 应该按排序顺序排在 A 之前。然后在某个时候,算法有可能会询问 "is B greater then A?" 而你的 compare(B, A) 也会 return 1 这意味着 B > A 并且 A 应该按排序顺序排在 B 之前。

你可以看到这个比较器的行为是完全不一致的。对于某些算法,这可能会导致无限循环。例如,一个算法可能会无休止地交换一对元素。