for循环包括if到parallelStream()表达式

时间:2016-06-06 11:18:52

标签: java lambda parallel-processing java-stream

有没有办法并行化这段代码:

HashMap<String, Car> cars;
List<Car> snapshotCars = new ArrayList<>();
...
for (final Car car : cars.values()) {
    if (car.isTimeInTimeline(curTime)) {
        car.updateCalculatedPosition(curTime);
        snapshotCars.add(car);
    }
}

更新:这是我在寻求帮助之前尝试过的:

snapshotCars.addAll(cars.values().parallelStream()
                                 .filter(c -> c.isTimeInTimeline(curTime))
                                 .collect(Collectors.toList()));

我怎样才能整合这条线? - &GT; car.updateCalculatedPosition(CURTIME);

3 个答案:

答案 0 :(得分:1)

好吧,假设updateCalculatedPosition不会影响运行它的Car对象之外的状态,那么使用peek可能足够安全:

List<Car> snapshotCars = cars.values()
    .parallelStream()
    .filter(c -> c.isTimeInTimeline(curTime))
    .peek(c -> c.updateCalculatedPosition(curTime))
    .collect(Collectors.toCollection(ArrayList::new));

我说这是足够安全&#34;因为collect指示peek将要查看哪些元素,这些元素必然是通过过滤器的所有项目。但是,请阅读this answer,了解为什么peek通常应该避免重要&#34;操作

您的无偷窥替代方案是首先,过滤和收集,然后使用完成的集合进行更新:

List<Car> snapshotCars = cars.values()
    .parallelStream()
    .filter(c -> c.isTimeInTimeline(curTime))
    .collect(Collectors.toCollection(ArrayList::new));
snapShotCars.parallelStream()
    .forEach(c -> c.updateCalculatedPosition(curTime));

从API的角度来看,这样更安全,但并行性更低 - 只有在完成过滤和收集后才开始更新位置。

答案 1 :(得分:0)

如果您希望对列表进行并行访问,则可能需要使用Collections.synchonizedList来获取线程安全列表:

List<Car> snapshotCars = Collections.synchronizedList(new ArrayList<>());

然后您可以像这样使用流API:

cars.values()
    .parallelStream()
    .filter(car -> car.isTimeInTimeline(curTime))
    .forEach(car -> {
        car.updateCalculatedPosition(curTime);
        snapshotCars.add(car);
    });

答案 2 :(得分:0)

RealSkeptic’s answer外,您还可以使用自己的收藏家:

List<Car> snapshotCars = cars.values().parallelStream()
    .filter(c -> c.isTimeInTimeline(curTime))
    .collect(ArrayList::new,
             (l,c) -> { c.updateCalculatedPosition(curTime); l.add(c); },
             List::addAll);

请注意,.collect(Collectors.toList()).collect(Collectors.toCollection(ArrayList::new))相同(但不一定相同),相当于.collect(ArrayList::new, List::add, List::addAll)

所以我们的自定义收集器执行类似的操作,但用一个函数替换累加器,该函数也执行所需的附加操作。