简体   繁体   English

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

[英]How to (globally) replace the common thread pool backend of Java parallel streams?

I would like to globally replace the common thread pool used by default by the Java parallel streams, ie, for example for 我想全局替换Java并行流默认使用的公共线程池,例如,

IntStream.range(0,100).parallel().forEach(i -> {
    doWork();
});

I know that it is possible to use a dedicated ForkJoinPool by submitting such instruction to a dedicated thread pool (see Custom thread pool in Java 8 parallel stream ). 我知道可以通过将这样的指令提交到专用线程池来使用专用的ForkJoinPool(请参阅Java 8并行流中的定制线程池 )。 The question here is 这里的问题是

  • Is it possible to replace the common ForkJoinPool by some other implementation (say a Executors.newFixedThreadPool(10) ? 是否可以通过其他一些实现方式替换常见的ForkJoinPool(例如, Executors.newFixedThreadPool(10)
  • Is it possible to do so by some global setting, eg, some JVM property? 是否可以通过某些全局设置(例如某些JVM属性)来执行此操作?

Remark: The reason why I like to replace the F/J pool is, because it appears to have a bug which makes it unusable for nested parallel loops. 备注:我之所以喜欢替换F / J池,是因为它似乎存在一个错误,使其无法用于嵌套并行循环。

Nested parallel loops have poor performance and may lead to deadlocks, see http://christian-fries.de/blog/files/2014-nested-java-8-parallel-foreach.html 嵌套并行循环的性能较差,并且可能导致死锁,请参阅http://christian-fries.de/blog/files/2014-nested-java-8-parallel-foreach.html

For example: The following code leads to a deadlock: 例如:以下代码导致死锁:

// 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
        });
    }
});

(even without any additional code at "do work here", given that parallelism is set to < 12). (即使并行度设置为<12,即使在“在这里工作”也不需要任何其他代码)。

My question is how to replace the FJP. 我的问题是如何更换FJP。 If you like to discuss nested parallel loops, you might check Nested Java 8 parallel forEach loop perform poor. 如果您想讨论嵌套并行循环,则可以检查嵌套Java 8并行forEach循环的执行情况。 Is this behavior expected? 这是预期的行为吗? .

I think that's not the way the stream API is intended to be used. 我认为这不是打算使用流API的方式。 It seems you're (mis)using it for simply doing parallel task execution (focusing on the task, not the data), instead of doing parallel stream processing (focusing on the data in the stream). 似乎您(错误地)将其用于简单地执行并行任务执行(专注于任务,而不是数据),而不是进行并行流处理(专注于流中的数据)。 Your code somehow violates some of the main principles for streams. 您的代码某种程度上违反了流的一些主要原则。 (I'm writing 'somehow' as it is not really forbidden but discouraged): Avoid states and side effects . (我在写“以某种方式”,因为它并不是真正被禁止的,但是不鼓励使用):避免出现状态和副作用

Apart from that (or maybe because of side effects), you're using heavy synchronization within your outer loop, which is everything else but harmless! 除此之外(或者可能是由于副作用),您还在外循环中使用大量同步,这一切都是无害的!

Although not mentioned in the documentation, parallel streams use the common ForkJoinPool internally. 尽管在文档中未提及,但并行流在内部使用公共的ForkJoinPool No matter whether or not this is a lack of documentation, we must simply accept that fact. 无论是否缺少文档,我们都必须接受这一事实。 The JavaDoc of ForkJoinTask states: ForkJoinTaskJavaDoc指出:

It is possible to define and use ForkJoinTasks that may block, but doing do requires three further considerations: (1) Completion of few if any other tasks should be dependent on a task that blocks on external synchronization or I/O. 可以定义和使用可能阻塞的ForkJoinTasks,但这样做还需要三点考虑:(1)如果有其他任务应依赖于在外部同步或I / O上阻塞的任务,则完成很少。 Event-style async tasks that are never joined (for example, those subclassing CountedCompleter) often fall into this category. 从未加入的事件样式的异步任务(例如,那些子类为CountedCompleter的子类)通常属于此类。 (2) To minimize resource impact, tasks should be small; (2)为了最大程度地减少资源影响,任务应该很小; ideally performing only the (possibly) blocking action. 理想情况下,仅执行(可能)阻止操作。 (3) Unless the ForkJoinPool.ManagedBlocker API is used, or the number of possibly blocked tasks is known to be less than the pool's ForkJoinPool.getParallelism level, the pool cannot guarantee that enough threads will be available to ensure progress or good performance. (3)除非使用ForkJoinPool.ManagedBlocker API,或者已知可能阻止的任务数小于池的ForkJoinPool.getParallelism级别,否则池无法保证有足够的线程可用以确保进度或良好的性能。

Again, it seems that you're using streams as replacement for a simple for-loop and an executor service. 同样,您似乎使用流代替了简单的for循环和执行程序服务。

  • If you just want to execute n tasks in parallel, use an ExecutionService 如果您只想并行执行n任务,请使用ExecutionService
  • If you have a more complex example where tasks are creating subtasks, consider using a ForkJoinPool (with ForkJoinTasks ) instead. 如果您有一个更复杂的示例,其中任务正在创建子任务,请考虑改为使用ForkJoinPool (带有ForkJoinTasks )。 (It ensures a constant number of threads without the danger of a deadlock because of too many tasks waiting for others to complete, as waiting tasks do not block their executing threads). (由于等待任务不会阻塞正在执行的线程,因此它确保了恒定数量的线程而没有死锁的危险,因为有太多任务等待其他任务完成)。
  • If you want to process data (in parallel), consider using the stream API. 如果要(并行)处理数据,请考虑使用流API。
  • You cannot 'install' a custom common pool . 您不能“安装”自定义公用池 It's created internally in private static code. 它是在内部使用私有静态代码创建的。
  • But you can take influence on the parallelism, the thread factory and the exception handler of the common pool using certain system properties (see JavaDoc of ForkJoinPool ) 但是您可以使用某些系统属性来影响并行性,线程工厂和公共池的异常处理程序(请参阅ForkJoinPool的JavaDoc

Don't mix up ExecutionService and ForkJoinPool . 不要混淆ExecutionServiceForkJoinPool They are (usually) not a replacement for each other! 它们(通常)不是彼此的替代品!

Although your original question is already answered well by isnot2bad , it might be important for you that the described bug (the reason for your wish to exchange the FJP implementation) seems to be fixed with java 1.8.0.40. 尽管isnot2bad已经很好地回答了您的原始问题,但对于您来说很重要的一点是,所描述的错误(希望交换FJP实现的原因)似乎已经用Java 1.8.0.40修复了。 See Nested Java 8 parallel forEach loop perform poor. 参见嵌套Java 8并行forEach循环执行不佳。 Is this behavior expected? 这是预期的行为吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM