Java ForkJoinPool 在 JDK17 中挂起

2024-01-07

以下代码可重复地与 JDK16 一起使用,并在我的笔记本电脑(4/8 核)上使用 JDK17 可重复地挂起,并使用基本命令行选项:“-ea”。存在 JDK 票证(https://bugs.openjdk.org/browse/JDK-8281524 https://bugs.openjdk.org/browse/JDK-8281524),但对于这种用法是否“好”存在分歧。然后,无线电在过去 6 个月里保持沉默。有人可以帮助查明我的使用错误(如果有)以及如何修复它吗?

import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.Stream;
import org.junit.Test;

public class FjpTest {

    @Test
    public void testFjp() {
        final ForkJoinPool fjPool = new ForkJoinPool(1);
        final String[] objs = Stream.generate(() -> "").limit(10_000).toArray(String[]::new);
        // the following line should sort the array,
        // but instead causes a single-threaded spin-wait
        fjPool.invoke(ForkJoinTask.adapt(() -> Arrays.parallelSort(objs))); // this hangs!
    }
}

Update 1(回应 Stephen C 的评论):

考虑这个示例,其中大量逻辑在自定义池中执行。这似乎不仅仅是“功能的重大损失”(因此 Open-JDK 票证上的“Priority=P3”),因为这在 JDK16 中有效。它还显示出 JDK17 本身的不兼容性,因为我们显然不能再将自定义池与集合框架一起使用。我仍然不确定如何解决这个问题。我唯一能想到的是,任何最初设计为在公共池中运行的东西都必须明确提交到公共池,这似乎是一个艰难的设计选择。我在忽略什么?

    new ForkJoinPool(1).invoke(ForkJoinTask.adapt(() -> {
        // ... some really smart and deep business logic in a ginormous application using
        // a custom ForkJoinPool, when an innocent developer or a library for that matter 
        // (not even realizing that it runs inside a custom ForkJoinPool) decides
        // to use the collections framework ...
        Arrays.parallelSort(Stream.generate(() -> "").limit(10_000).toArray(String[]::new));
        // ... dead code from here ...
    }));

我对 Doug Lea 在票证上所说内容的解释是,问题的原因是您的用例导致两个人之间共享工作ForkJoinPool实例,而且这永远不能保证有效。

现在我明白为什么会发生共享了。这javadoc https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Arrays.html#parallelSort(T%5B%5D) for public static <T extends Comparable<? super T>> void parallelSort(T[] a) state:

The ForkJoin公共池用于执行任何并行任务。

因此,通过在调用的自定义池中启动任务parallelSort您正在设置跨池工作共享的条件。

答案似乎是“不要这样做”。不要打电话parallelSort来自自定义任务ForkJoinPool. The Arrays.parallelSort方法不提供指定要使用的池的方法。相反,只需在公共池中启动您的任务即可。

我通过更改暂时确认了这一点:

    final ForkJoinPool fjPool = new ForkJoinPool(1);

在你的例子中

    final ForkJoinPool fjPool = ForkJoinPool.commonPool();

这似乎有效。这可能不是您想要的解决方案,但我认为这是您能得到的最好的解决方案,除非您能说服 Doug Leaet al that:

  • 应支持跨池工作共享,
  • 或者应该提供一种方法来告诉Arrays.parallelSort使用指定的ForkJoinPool.

就我个人而言......我不相信这些修复中的任何一个都是一个好主意。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java ForkJoinPool 在 JDK17 中挂起 的相关文章

随机推荐