Java8 Stream reduce 归约的并发注意事项。combiner.apply(u, accumulator.apply(identity, t))理解

reduce概念

下面解释是抄别人的。和haskell等语言里的概念很像

好的命名是自解释的 reduce的方法取得就是其中归纳的含义 java8 流相关的操作中,我们把它理解
“累加器”,之所以加引号是因为他并不仅仅是加法 他的运算可以是一个Lambda 表达式 所以更准确的说 reduce 是一个迭代运算器
Stream包的文档中其实已经说的很明白了 但是就是因为不是很理解所以看的云里雾里 其中说到:
一个reduce操作(也称为折叠)接受一系列的输入元素,并通过重复应用操作将它们组合成一个简单的结果

并发的问题

函数介绍

  • reduce(accumulator)
  • reduce(identity,accumulator)
  • reduce(identity,accumulator,combiner)
    identityreduce进行迭代操作的初始值。accumulator是用来迭代的。combiner是并发时用来合并各线程结果的。

代码

public class AppTest {
    /**
     * Rigorous Test :-)
     */
    @Test
    public void test2() {
        assertTrue(true);
        int b = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).parallel().reduce(0, (acc, x) -> acc + x);
        int c = Stream.of(2, 3, 4, 5, 6, 7, 8, 9).parallel().reduce(1, (acc, x) -> acc + x);
        int d = Stream.of(2, 3, 4, 5, 6, 7, 8, 9).parallel().reduce(1, (acc, x) -> acc + x, (x, y) -> x + y - 1);
        System.out.printf("初始值个数不影响结果:%d\n", b);
        System.out.printf("无修正:%d\n", c);
        System.out.printf("合并修正:%d\n", d);
    }
}

结果

在这里插入图片描述


可以明显看到第二个方式是有问题的。原因是初始值加了四遍。这是由于他内部是使用了fork-join框架 把大任务转小任务,然后并发运行。有点像归并排序的感觉。但是为了保证并发安全,他把每个输入数据都复制了一份,这样自然不用🔓了,但同时导致初始值多加三遍。所以redue源代码注释里才会有这句话。

combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)

和这句话

combiner(identity, u) is equal to u

这两句话只要满足一个就行了。
在这个例子里,初始值为0当然是符合的,为1 是不符合的。

我们这里可以把思维再扩展些。这里的等于并不是要求地址相等是同一个对象,而只是要求逻辑上等价

话说这也太卷了,我就做个累加也要并发。😃

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值