下面的代码可重用地使用JDK16,并在我的膝上型计算机(4/8核心)上使用基本命令行选项"-ea“可再现地挂起JDK17。JDK-票证存在(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!
}
}更新1 (针对Stephen的评论):
考虑在自定义池中执行大量逻辑的示例。这不仅是“函数的重大损失”(因此在Open票证上出现了"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 ...
}));发布于 2022-08-24 15:26:51
我对Doug在票证上的解释是,造成问题的原因是您的用例导致了两个ForkJoinPool实例之间的工作共享,而这从来没有得到保证。
现在我明白了为什么分享会发生。javadoc for public static <T extends Comparable<? super T>> void parallelSort(T[] a)状态:
ForkJoin公共池用于执行任何并行任务。
因此,通过在调用parallelSort的自定义池中启动一个任务,您将设置跨池工作共享的条件。
答案似乎是“不要那样做”。不要从自定义parallelSort中的任务调用ForkJoinPool。Arrays.parallelSort方法没有提供指定要使用的池的方法。相反,只需在公共池中启动任务即可。
我已通过更改来初步证实这一点:
final ForkJoinPool fjPool = new ForkJoinPool(1);在你的例子中
final ForkJoinPool fjPool = ForkJoinPool.commonPool();而且看起来很管用。这可能不是你想要的解决方案,但我认为这是你能得到的最好的解决方案,除非你能说服Doug等人:
Arrays.parallelSort使用指定的ForkJoinPool。个人..。我不相信这些修正都是个好主意。
https://stackoverflow.com/questions/73474536
复制相似问题