我有这个代码a:
print("Response data: \(JSON[1]["Name"] as! String)")
和此代码b:
ComparisonResults comparisonResults = requestsList
.stream()
.map(item -> getResponse(item))
.map(item -> compareToBl(item))
.reduce(new ComparisonResults(), (result1, result2) ->
{
result1.addSingleResult(result2);
// return result1;
return new ComparisonResults(result1);
});
我所做的就是创建响应对象,然后将它们转换为comaprisonResult对象并将它们缩减为一个comaprisonResult。
代码 ComparisonResults comparisonResults = requestsList
.parallelStream()
.map(item -> getResponse(item))
.map(item -> compareToBl(item))
.reduce(new ComparisonResults(), (result1, result2) ->
{
result1.addSingleResult(result2);
// return result1;
return new ComparisonResults(result1);
});
显示了一个正确的int类成员a
代码comparisonResults.num_of_sub_responses==5
显示一个int类成员b
,它是正确结果的两倍。
java 8 reduce应该是线程安全的,对吧?
我错过了什么吗? comparisonResults.num_of_sub_responses==10
和getResponse
是线程安全的
答案 0 :(得分:7)
您正在改变reduce
中的传入对象。这是错的。在修改传入对象之后创建新对象没有任何帮助。
你想做什么,是
.collect(ComparisonResults::new, ComparisonResults::addSingleResult,
(a,b)->/* code to merge two ComparisonResults instances*/);
如果.map(item -> compareToBl(item))
的结果为ComparisonResults
,或者换句话说,addSingleResult
合并了两个ComparisonResults
个实例,则可以使用ComparisonResults::addSingleResult
作为合并功能,虽然它的名字有点误导。
你应该仔细阅读“Reduction” chapter of the documentation及其后续行动,“可变减少”。
答案 1 :(得分:2)
reduce操作reduce(identity, operator)
依赖于关于你传递它的参数的两个重要假设。
identity
之间使用reduce运算符时,您将获得原始项目。这两个假设在使用并行流时非常重要,因为一般来说,它的作用是:
每个线程都以标识开头,并使用流中的元素累积结果:
result = identity op element1 op element2 op element3 ...
然后使用运算符将来自不同线程的结果组合在一起:
grand result = result1 op result2 op result3
因此,假设您正在对数字求和,它会将5 + 4 + 3 + 20
之类的操作分解为( 0 + 5 + 4 ) + ( 0 + 3 + 20 )
。当且仅当上述假设成立时才有效。 (0是加法的标识,加法是关联的)。
但是通过改变运算符中的第一个操作数,这意味着您实际上正在改变身份对象。因此,它不再被视为身份。那是op(identity,result)
并没有给你与result
本身相同的价值。
如果操作员不是关联的,那么问题将在“宏观结果”阶段出现。