如何(全局)替换Java并行流的公共线程池后端?

如何(全局)替换Java并行流的公共线程池后端?,java,multithreading,concurrency,parallel-processing,stream,Java,Multithreading,Concurrency,Parallel Processing,Stream,我希望全局替换Java并行流默认使用的公共线程池,例如 IntStream.range(0,100).parallel().forEach(i -> { doWork(); }); 我知道,通过将此类指令提交到专用线程池,可以使用专用的ForkJoinPool(请参阅)。这里的问题是 是否可以用其他实现(例如Executors.newFixedThreadPool(10))替换公共ForkJoinPool 是否可以通过一些全局设置(例如,一些JVM属性)来实现这一点 备注:我

我希望全局替换Java并行流默认使用的公共线程池,例如

IntStream.range(0,100).parallel().forEach(i -> {
    doWork();
});
我知道,通过将此类指令提交到专用线程池,可以使用专用的ForkJoinPool(请参阅)。这里的问题是

  • 是否可以用其他实现(例如
    Executors.newFixedThreadPool(10)
    )替换公共ForkJoinPool
  • 是否可以通过一些全局设置(例如,一些JVM属性)来实现这一点
备注:我喜欢替换F/J池的原因是,它似乎有一个bug,使得它不能用于嵌套的并行循环

嵌套并行循环的性能较差,可能导致死锁,请参阅

例如:以下代码导致死锁:

// Outer loop
IntStream.range(0,24).parallel().forEach(i -> {

    // (omitted:) do some heavy work here (consuming majority of time)

    // Need to synchronize for a small "subtask" (e.g. updating a result)
    synchronized(this) {
        // Inner loop (does s.th. completely free of side-effects, i.e. expected to work)
        IntStream.range(0,100).parallel().forEach(j -> {
            // do work here
        });
    }
});
(考虑到并行度设置为<12,即使在“DoWorkhere”没有任何附加代码)


我的问题是如何替换FJP。如果您想讨论嵌套的并行循环,您可以检查。

我认为这不是流API的使用方式。似乎您(错误地)使用它只是为了执行并行任务(关注任务,而不是数据),而不是执行并行流处理(关注流中的数据)。您的代码在某种程度上违反了流的一些主要原则。(我写的是“不知何故”,因为这不是真正禁止的,而是不鼓励的):避免

除此之外(或者可能是因为副作用),您在外部循环中使用了大量同步,这是其他一切,但无害

尽管文档中未提及,但并行流在内部使用。无论这是否是缺少文档,我们必须接受这一事实。这些国家:

可以定义和使用可能阻塞的ForkJoinTasks,但这样做需要进一步考虑三个因素:(1)如果任何其他任务依赖于阻塞外部同步或I/O的任务,则完成很少的任务。事件样式异步任务从未联接(例如,那些子类化CountedCompleter的任务)通常属于这一类。(2)为了最小化资源影响,任务应该很小;理想情况下,只执行(可能的)阻塞操作。(3)除非使用ForkJoinPool.ManagedBlocker API,或者已知可能被阻止的任务数小于池的ForkJoinPool.getParallelism级别,否则池无法保证有足够的线程可用以确保进度或良好性能

同样,您似乎正在使用流来替代简单的for循环和executor服务

  • 如果您只想并行执行
    n
    任务,请使用
    ExecutionService
  • <> LI>如果有一个更复杂的例子,任务在创建子任务,那么考虑使用<代码> FokCuangPosie(使用<代码> FokJojTungs[/COD>)。(它确保了不存在死锁的恒定数量的线程,因为太多的任务等待其他人完成,因为等待任务不会阻塞它们的执行线程) 如果要处理数据(并行),请考虑使用流API。
  • 您不能“安装”自定义项。它是在私有静态代码中内部创建的
  • 但是,您可以使用某些系统属性影响公共池的并行性、线程工厂和异常处理程序(请参阅)

不要混淆
ExecutionService
ForkJoinPool
。它们(通常)不是彼此的替代品!

尽管您最初的问题已经由
,对您来说,描述的bug(您希望交换FJP实现的原因)可能很重要java 1.8.0.40似乎已修复。请参见

您一直在这里和并发兴趣列表上发布相同的问题。在这里发布之前,等待Doug的回答。@edharned:在该列表上,他们总是开始关于生成的补偿线程等的学术讨论(这可能解释了性能受到的小影响).在我的测试中,我打印了所有的线程,但我遇到了一个死锁,没有任何补偿线程。我只是想修复一个可能严重的错误。因为我没有得到任何与该错误相关的答案,所以我正在考虑像霍尔格那样更换FJP。所以我不想再开始这件事。我想更换FJP。-也许我应该转向一些other framework?Akka Streams?Scala?有什么建议吗?这里的人不知道那里说了什么,所以这里的人会发布重复的问题/答案。我同意FJP是错误的。今天没有建议。最终Oracle将不得不做一些激进的事情来取代它,但我怀疑不会很快。阅读java文档。它不是并行执行框架工作。这就是为什么我们有ExecutorService。它到底应该做什么?生成100个线程?parallel()可能是一个误导性的名称,但如果您阅读手册并学习语义,它是一个性能非常好的框架。parallel()不会神奇地加快代码的速度。在这种情况下,并行意味着任务被递归地拆分并在多个核上处理。是的,它增加了堆栈使用率,但我最近读到一篇关于JVM的文章,说这种问题是高度优化的。流不是循环的替代品。Java仍然是一种非常必要的工具Streams擅长于集合操作。您可以基于ExecutorService轻松编写自己的stream impl。感谢您和+1给出部分(尽管是否定的)回答。关于你的其他评论:我之所以喜欢替换FJP,是因为它有一个bug。这个bug也是嵌套循环性能非常差的原因。在我的应用程序中,这一点同步是无害的(大约一小块代码),但我不喜欢仅仅因为一个bug而重新设计我的整个框架