但即使resourceMemory
是一个线程安全集合,您的代码仍然被破坏,因为您的filter
条件与终端操作之间存在干扰。 .filter(o -> !resourceMemory.contains(o))
查询您在终端操作中修改的相同列表,并且不应该很难理解即使使用线程安全集合,这也能如何制动:
两个或多个线程可能会处理过滤器,并发现该元素不包含在列表中,那么所有的人都会添加的元素,矛盾没有重复你的意图明显。
你可以诉诸forEachOrdered
这将执行的操作顺序和非并发:
body.getSurroundings().parallelStream()
.filter(o -> o instanceof ResourcePoint)
.map(o -> (ResourcePoint)o)
.forEachOrdered(o -> {// not recommended, just for explanation
if(!resourceMemory.contains(o))
resourceMemory.add(o);
});
这将工作,很明显你怎么可以加入到这一行动中的另一个列表,但它远是远推荐的编码风格。此外,这个终端动作与所有处理线程同步的事实会破坏并行处理的任何潜在的好处,特别是作为该流管道的最昂贵的操作是在一个LinkedList
将(必须)发生单线程调用contains
。
收集流元素到列表中正确的方法是通过,顾名思义,collect
:
List<ResourcePoint> resourceMemory
=body.getSurroundings().parallelStream()
.filter(o -> o instanceof ResourcePoint)
.map(o -> (ResourcePoint)o)
.distinct() // no duplicates
.collect(Collectors.toList()); // collect into a list
这不返回LinkedList
,但是你应该认真重新考虑你是否真的需要一个LinkedList
。在所有病例的99%中,你没有。如果您真的需要需要LinkedList
,您可以用Collectors.toCollection(LinkedList::new)
替换Collectors.toList()
。
现在,如果您确实必须添加到您的控件之外创建的现有列表(可能已包含元素),则应考虑上述事实,您必须确保单线程访问非线程安全无论如何,所以从并行流中完全没有任何好处。在大多数情况下,它更有效地从该名单独立让流工作,并在单线程一步之后添加的结果:
Set<ResourcePoint> newElements=
body.getSurroundings().parallelStream()
.filter(o -> o instanceof ResourcePoint)
.map(o -> (ResourcePoint)o)
.collect(Collectors.toCollection(LinkedHashSet::new));
newElements.removeAll(resourceMemory);
resourceMemory.addAll(newElements);
在这里,我们收集到LinkedHashSet
这意味着遭遇秩序的维护和排序删除新元素中的重复项,然后在新元素上使用removeAll
删除目标列表中的现有元素(这里我们从临时集合的哈希集性质中受益),最后,将新元素添加到目标列表中,如上所述,无论如何,对于不是线程安全的目标集合,必须发生单线程。
使用此解决方案将newElements
添加到其他目标集合很容易,比在流处理期间编写用于生成两个列表的自定义收集器要容易得多。但请注意,上面所写的流操作过于勉强以至于不能从并行处理中获益。您需要大量的元素来补偿最初的多线程开销。甚至有可能没有任何数字能够得到回报。
您可以使用'peek()'或自定义收集器。 –
你的意思是'instanceof ResourcePoint'或'o.getClass()== ResourcePoint.class'吗?决定一个,但不要使用混淆实际意图的'o.getClass()。equals(ResourcePoint.class)'。此外,使用并行流时,您的代码会以多种方式被破解。请仔细阅读https://docs.oracle.com/javase/8/docs/api/?java/util/stream/package-summary.html。 – Holger
问题的严格答案是'.forEach(o - > {resourceMemory.add(o); myOtherList.add(o);})'。但请注意Holger的评论。您需要更多地了解您想要解决此问题的真正目标。 – Tunaki