Java 8并行流问题

4
    _logger.info("data size : "+saleData.size);

    saleData.parallelStream().forEach(data -> {
                SaleAggrData saleAggrData = new SaleAggrData() {
                    {
                        setCatId(data.getCatId());
                        setRevenue(RoundUpUtil.roundUpDouble(data.getRevenue()));
                        setMargin(RoundUpUtil.roundUpDouble(data.getMargin()));
                        setUnits(data.getUnits());
                        setMarginRate(ComputeUtil.marginRate(data.getRevenue(), data.getMargin()));
                        setOtd(ComputeUtil.OTD(data.getRevenue(), data.getUnits()));
                        setSaleDate(data.getSaleDate());
                        setDiscountDepth(ComputeUtil.discountDepth(data.getRegularPrice(), data.getRevenue()));
                        setTransactions(data.getTransactions());
                        setUpt(ComputeUtil.UPT(data.getUnits(), data.getTransactions()));
                    }
                };
                salesAggrData.addSaleAggrData(saleAggrData);
            });

代码的问题在于从数据库获取响应时,使用并行流进行迭代时,数据大小每次都不同,而使用串行流时却运行良好。但我不能使用串行流,因为数据量巨大,需要花费很长时间。任何线索都将非常有帮助。

1
请注意 - 您正在使用 SaleAggrData 类的匿名子类,这是不必要的。这将会对性能产生影响,因为在运行时必须加载额外的类。最好使用 SaleAggrData sad = new SaleAggrData(); sad.setCatId(...); sad.setRevenue(...); ...在此处查看性能影响测量结果 - MC Emperor
但是数据大小在流执行之前已经记录下来了...你在说什么? - Jean-Baptiste Yunès
salesAggrData 是一个线程安全的集合吗? - Jean-Baptiste Yunès
1个回答

10
你正在并行添加元素到salesAggrData,我假设这是一些Collection。如果它不是线程安全的Collection,那么你得到不一致的结果也就不足为奇了。
与其使用forEach,为什么不使用map(),然后将结果收集到某个Collection中呢?
List<SaleAggrData> salesAggrData =
    saleData.parallelStream()
            .map(data -> {
                    SaleAggrData saleAggrData = new SaleAggrData() {
                        {
                            setCatId(data.getCatId());
                            setRevenue(RoundUpUtil.roundUpDouble(data.getRevenue()));
                            setMargin(RoundUpUtil.roundUpDouble(data.getMargin()));
                            setUnits(data.getUnits());
                            setMarginRate(ComputeUtil.marginRate(data.getRevenue(), data.getMargin()));
                            setOtd(ComputeUtil.OTD(data.getRevenue(), data.getUnits()));
                            setSaleDate(data.getSaleDate());
                            setDiscountDepth(ComputeUtil.discountDepth(data.getRegularPrice(), data.getRevenue()));
                            setTransactions(data.getTransactions());
                            setUpt(ComputeUtil.UPT(data.getUnits(), data.getTransactions()));
                        }
                    };
                    return saleAggrData;
            })
            .collect(Collectors.toList());

顺便说一下,我可能会改变那个匿名类实例的创建方式,使用一个命名类的构造函数来创建SaleAggrData实例。


1
我可能会使用顺序流,因为并行流可能会使事情变得更慢,大部分时间可能都花在执行查询和加载结果上,而不是转换它们。 - JB Nizet
@JBNizet 或许你是正确的,但测试并行流与顺序流的性能也无妨。 - Eran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接