当前位置: 首页 > 面试题库 >

Java 8,在流中使用.parallel会导致OOM错误

慕宏峻
2023-03-14
问题内容

Java 8 In Action
一书的第7.1.1节中,作者指出,通过添加功能,流可以从并行处理中受益.parallel()。他们提供了一个简单的方法parallelSum(int)来说明这一点。我很好奇它的工作原理,所以我执行了以下代码:

package lambdasinaction.chap7;

import java.util.stream.Stream;

public class ParallelPlay {

    public static void main(String[] args) {
        System.out.println(parallelSum(100_000_000));
    }

    public static long parallelSum(long n) {
        return Stream.iterate(1L, i -> i + 1)
                .limit(n)
                .parallel()
                .reduce(0L, Long::sum);
    }
}

令我惊讶的是,我收到此错误:

Exception in thread "main" java.lang.OutOfMemoryError
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at java.util.concurrent.ForkJoinTask.getThrowableException(Unknown Source)
    at java.util.concurrent.ForkJoinTask.reportException(Unknown Source)
    at java.util.concurrent.ForkJoinTask.invoke(Unknown Source)
    at java.util.stream.SliceOps$1.opEvaluateParallelLazy(Unknown Source)
    at java.util.stream.AbstractPipeline.sourceSpliterator(Unknown Source)
    at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
    at java.util.stream.ReferencePipeline.reduce(Unknown Source)
    at lambdasinaction.chap7.ParallelPlay.parallelSum(ParallelPlay.java:15)
    at lambdasinaction.chap7.ParallelPlay.main(ParallelPlay.java:8)
Caused by: java.lang.OutOfMemoryError: Java heap space
    at java.util.stream.SpinedBuffer.ensureCapacity(Unknown Source)
    at java.util.stream.Nodes$SpinedNodeBuilder.begin(Unknown Source)
    at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
    at java.util.stream.SliceOps$SliceTask.doLeaf(Unknown Source)
    at java.util.stream.SliceOps$SliceTask.doLeaf(Unknown Source)
    at java.util.stream.AbstractShortCircuitTask.compute(Unknown Source)
    at java.util.concurrent.CountedCompleter.exec(Unknown Source)
    at java.util.concurrent.ForkJoinTask.doExec(Unknown Source)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(Unknown Source)
    at java.util.concurrent.ForkJoinPool.runWorker(Unknown Source)
    at java.util.concurrent.ForkJoinWorkerThread.run(Unknown Source)

我在Windows 7 SP1上使用四核处理器运行Java 1.8.0_45。这是怎么回事?


问题答案:

在这里,您可以创建无限流并在之后对其进行限制。关于并行处理无限流存在已知问题。特别是,无法有效地将任务分成相等的部分。在内部使用了一些启发式方法,这些启发式方法不太适合每个任务。在您的情况下,最好使用创建有限流LongStream.range

import java.util.stream.LongStream;

public class ParallelPlay {

    public static void main(String[] args) {
        System.out.println(parallelSum(100_000_000));
    }

    public static long parallelSum(long n) {
        return LongStream.rangeClosed(1, n).parallel().sum();
    }
}

在这种情况下,Stream引擎从一开始就知道您有多少个元素,因此它可以有效地拆分任务。另请注意,使用LongStream会更有效,因为您将没有不必要的装箱。

通常,如果可以用有限的流解决任务,请避免使用无限的流。



 类似资料:
  • 我正在使用四核处理器的Windows7,SP1上运行Java1.8.0_45。有事吗?

  • 我正在尝试使用NPM的gulp-git模块推送到我的远程存储库。add&commit部分运行良好,但在尝试执行远程推送时遇到流错误。 TypeError:undefined不是write(C:\src\git\ig\node_module\gulp-git\node_module\through2\node_module\readable-stream\lib_stream_readable.js

  • 我试图以以下方式使用Jersey的@BeanParam注释: 这是我的豆子: 这是需要使用它的资源方法: 现在我想使用一个单元测试来测试它,该单元测试使用以下url向测试服务器发送超文本传输协议请求: GET超文本传输协议://path_to_resource?参数1 我的问题是,这导致了415响应,泽西打印了这条消息: 找不到Java类BeanParamModel、Java类型类BeanPara

  • 在本例中,我在一个包含2个副本的部署中运行“echoheaders”Nginx。当我删除一个pod时,我有时会收到约40秒的缓慢响应和错误。 我们正在库伯内特斯运行我们的API网关,并且需要能够允许库伯内特斯调度程序在它认为合适的时候处理pod。 我们最近想引入会话相关性,为此,我们想迁移到新的闪亮的NEG:网络endpoint组:https://cloud.google.com/load-bal

  • 我是WPF/XAML的新手。如果绑定到XAML中错误的数据类型,我希望得到一条错误消息。XAML似乎希望所有绑定都通过字符串进行,但是如果错误地使用int或double则不会出现错误消息。 我在这里找到了以下XAML代码: 我发现绑定可以在int属性上工作,但不能在公共int字段上工作。下面是我创建的一个Point类来测试它: 如果绑定到int属性X或string属性Xstr,它可以正常工作。如果

  • 在kotlin引用的属性和字段一节中,写了以下示例: var AllByDefault:int?//错误:需要显式初始化器,隐含默认getter和setter @toniedzwiedz的回答解决了这个问题。这是我的错.我把属性和变量搞错了。