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

Java8流的顺序执行和并行执行产生不同的结果?

竺承望
2023-03-14
问题内容

在Java8中运行以下流示例:

    System.out.println(Stream
        .of("a", "b", "c", "d", "e", "f")
        .reduce("", (s1, s2) -> s1 + "/" + s2)
    );

产量:

/a/b/c/d/e/f

当然-这并不奇怪。由于http://docs.oracle.com/javase/8/docs/api/index.html?overview-
summary.html
,流是顺序执行还是并行执行都没有关系:

除了标识为明确不确定的操作(例如findAny())之外,流是顺序执行还是并行执行都不应该更改计算结果。

AFAIK reduce()是确定性的并且(s1, s2) -> s1 + "/" + s2是关联的,因此加法parallel()应产生相同的结果:

    System.out.println(Stream
            .of("a", "b", "c", "d", "e", "f")
            .parallel()
            .reduce("", (s1, s2) -> s1 + "/" + s2)
    );

但是我的机器上的结果是:

/a//b//c//d//e//f

怎么了

顺便说一句:使用(首选).collect(Collectors.joining("/"))而不是reduce(...)产生相同的结果a/b/c/d/e/f顺序执行和并行执行。

JVM详细信息:

java.specification.version: 1.8
java.version: 1.8.0_31
java.vm.version: 25.31-b07
java.runtime.version: 1.8.0_31-b13

问题答案:

从reduce的文档中:

身份值必须是累加器功能的身份。这意味着对于所有t,accumulator.apply(identity,t)等于t。

在您的情况下,这是不正确的-“”和“ a”创建了“ / a”。

我已经提取了累加器功能并添加了打印输出以显示发生了什么:

BinaryOperator<String> accumulator = (s1, s2) -> {
    System.out.println("joining \"" + s1 + "\" and \"" + s2 + "\"");
    return s1 + "/" + s2;
};
System.out.println(Stream
                .of("a", "b", "c", "d", "e", "f")
                .parallel()
                .reduce("", accumulator)
);

这是示例输出(运行之间有所不同):

joining "" and "d"
joining "" and "f"
joining "" and "b"
joining "" and "a"
joining "" and "c"
joining "" and "e"
joining "/b" and "/c"
joining "/e" and "/f"
joining "/a" and "/b//c"
joining "/d" and "/e//f"
joining "/a//b//c" and "/d//e//f"
/a//b//c//d//e//f

您可以在函数中添加if语句以分别处理空字符串:

System.out.println(Stream
        .of("a", "b", "c", "d", "e", "f")
        .parallel()
        .reduce((s1, s2) -> s1.isEmpty()? s2 : s1 + "/" + s2)
);

正如Marko Topolnik所注意到的,s2由于累加器不必是可交换的函数,因此不需要进行检查。



 类似资料:
  • 在Java8中运行以下流示例: 产量: 当然,这并不奇怪。由于http://docs.oracle.com/javase/8/docs/api/index.html?overview-summary.html,流是顺序执行还是并行执行并不重要: 顺便说一下:使用(首选的)而不是生成相同的结果,用于顺序和并行执行。 JVM详细信息:

  • 问题内容: 我们有一个基于石英的调度程序应用程序,该应用程序每分钟运行约1000个作业,每分钟的秒数均匀分布,即每秒约16-17个作业。理想情况下,这16-17个作业应同时触发,但是该作业的execute方法的第一个语句(仅记录执行时间)非常晚。例如,假设我们从05:00到05:04每分钟安排1000个作业。因此,理想情况下,计划在05:03:50进行的作业应该在05:03:50记录了execut

  • 本文向大家介绍setTimeout和Promise的执行顺序?相关面试题,主要包含被问及setTimeout和Promise的执行顺序?时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 首先我们来看这样一道题: 输出答案为2 10 3 5 4 1 要先弄清楚settimeout(fun,0)何时执行,promise何时执行,then何时执行 settimeout这种异步操作的回调,只有主线程

  • 从流javadoc: 顺序流/并行流之间没有功能上的区别。输出从不受执行模式影响。 由于性能提高,在给定适当的核数和问题大小以证明开销合理的情况下,并行流始终是优选的。 我们希望编写一次代码并在任何地方运行,而不必关心硬件(毕竟这是Java) 假设这些假设是有效的(有一点元假设没有问题),那么在API中公开执行模式有什么价值呢? 看起来您应该能够声明一个,顺序/并行执行的选择应该在下面的一个层中自

  • 脚本是一个命令一个命令顺序执行的。 Selenese 本身不支持条件语句(if - else, 等)或循环迭代(for, while, 等)。没有流程控制也可以制作很多有用的测试案例。然而,对于动态内容的功能测试,可能涉及到多个页面,编程逻辑通常是必要的。 如果必须使用流程控制,有以下三种解决方案: 使用 Selenium RC 运行脚本结合客户端库,如:Java 或 PHP 库,利用编程语言的流

  • 问题内容: 我正在使用rub redis宝石。想知道我是否例如: 这样的执行顺序得到保证吗? 问题答案: 当然可以保证顺序,否则流水线将毫无用处。您可以随时查看代码。例如,此测试明确假定命令是按顺序执行的:https : //github.com/redis/redis- rb/blob/master/test/pipelining_commands_test.rb#L32