在阅读Java流文档时,我了解到:
(new ArrayList<String>().stream().spliterator().characteristics() & Spliterator.CONCURRENT) != 0
应评估为true。但是,在测试时不会。
我想念什么。
我指的是Java文档: https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
无干扰
使用流,您可以对各种数据源执行可能并行的聚合操作,甚至包括非线程安全的集合(例如ArrayList)。这只有在我们可以防止流管道执行期间干扰数据源的情况下才有可能。除了转义hatch操作iterator()和spliterator()之外,执行都在调用终端操作时开始,并在终端操作完成时结束。对于大多数数据源,防止干扰意味着确保在流管道执行期间根本不修改数据源。值得注意的例外是流的源是并发集合,这些流是专门为处理并发修改而设计的。并发流源是那些其分隔符报告CONCURRENT特性的源。 因此,源可能不是并发的流管道中的行为参数永远不应修改流的数据源。如果行为参数修改或导致修改流的数据源,则该行为参数会干扰非并行数据源。无干扰的需求适用于所有管道,而不仅仅是并行管道。除非流源是并发的,否则在执行流水线期间修改流的数据源可能会导致异常,错误的答案或不一致的行为。对于行为良好的流源,可以在终端操作开始之前修改源,并且这些修改将反映在所涵盖的元素中。例如,考虑以下代码:
List<String> l = new ArrayList(Arrays.asList("one", "two")); Stream<String> sl = l.stream(); l.add("three"); String s = sl.collect(joining(" "));
首先创建一个列表,该列表由两个字符串组成:“一个”;和“两个”。然后从该列表创建一个流。接下来,通过添加第三个字符串“三”来修改列表。最后,将流中的元素收集起来并结合在一起。由于列表是在终端收集操作开始之前修改的,因此结果将是字符串“一二三”。从JDK集合返回的所有流以及大多数其他JDK类都以这种方式表现良好。有关其他库生成的流的信息,请参阅低级流构建以了解构建行为良好的流的要求。
我也尝试了CopyOnWriteArrayList。那里也没有设置CONCURRENT标志。例如,对于ConcurrentLinkedQueue,将设置CONCURRENT标志。
我正在将Oracle javaSe-11与jdk-11.0.2一起使用。
答案 0 :(得分:3)
特征值表示元素源可以由多个线程安全地并发修改(允许添加,替换和/或移除),而无需外部同步。
请注意,此实现未同步。。如果多个线程同时访问
ArrayList
实例,并且至少有一个线程在结构上修改了列表,则它必须从外部进行同步。 (结构修改是添加或删除一个或多个元素的任何操作,…
很难说ArrayList
作为流源只是CONCURRENT
之外的一切。
您引用的文档并不矛盾。但是我不得不承认,如果在“对于行为良好的流媒体源……”之前有一段段落的休息,以便让读者休息一下,然后反思一下之前所说的话,那会更好得多。一个不同的观点,适用于ArrayList
以及所有其他“行为良好的流源”,但不再与CONCURRENT
特征相关,并且不影响所描述的行为参数的约束之前。
所有新要点是,您可以在流的终端操作开始之前更改ArrayList
,但仍然只能从一个线程(或您自己进行同步)开始,但仍然不允许您在正在进行的终端操作期间进行结构修改,这会阻止行为参数进行任何结构修改,因为这些参数总是在进行中的终端操作期间进行评估。
CopyOnWriteArrayList
的情况有所不同,它不会具有CONCURRENT
特征,因为它的分隔符将具有IMMUTABLE
特征,因为您将遍历不可变的快照;对原始CopyOnWriteArrayList
的修改不会影响流。
答案 1 :(得分:0)
CopyOnWriteArrayList:从名称可以明显看出,每次写入都会创建一个新副本。 ConcurrentLinkedQueue:允许使用Lock对象数组进行并发写入