简体   繁体   中英

Why does ArrayList stream not report CONCURRENT characteristics?

When reading the documentation to java streams I understand that:

(new ArrayList<String>().stream().spliterator().characteristics() & Spliterator.CONCURRENT) != 0

Should evaluate to true. However, when testing this, it does not.

What am I missing.

The java documentation I am referring to: https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

Non-interference

Streams enable you to execute possibly-parallel aggregate operations over a variety of data sources, including even non-thread-safe collections such as ArrayList. This is possible only if we can prevent interference with the data source during the execution of a stream pipeline. Except for the escape-hatch operations iterator() and spliterator(), execution begins when the terminal operation is invoked, and ends when the terminal operation completes. For most data sources, preventing interference means ensuring that the data source is not modified at all during the execution of the stream pipeline. The notable exception to this are streams whose sources are concurrent collections, which are specifically designed to handle concurrent modification. Concurrent stream sources are those whose Spliterator reports the CONCURRENT characteristic. Accordingly, behavioral parameters in stream pipelines whose source might not be concurrent should never modify the stream's data source. A behavioral parameter is said to interfere with a non-concurrent data source if it modifies, or causes to be modified, the stream's data source. The need for non-interference applies to all pipelines, not just parallel ones. Unless the stream source is concurrent, modifying a stream's data source during execution of a stream pipeline can cause exceptions, incorrect answers, or nonconformant behavior. For well-behaved stream sources, the source can be modified before the terminal operation commences and those modifications will be reflected in the covered elements. For example, consider the following code:

  List<String> l = new ArrayList(Arrays.asList("one", "two")); Stream<String> sl = l.stream(); l.add("three"); String s = sl.collect(joining(" ")); 

First a list is created consisting of two strings: "one"; and "two". Then a stream is created from that list. Next the list is modified by adding a third string: "three". Finally the elements of the stream are collected and joined together. Since the list was modified before the terminal collect operation commenced the result will be a string of "one two three". All the streams returned from JDK collections, and most other JDK classes, are well-behaved in this manner; for streams generated by other libraries, see Low-level stream construction for requirements for building well-behaved streams.

I have also tried with CopyOnWriteArrayList. There the CONCURRENT flag is also not set. While for instance for ConcurrentLinkedQueue the CONCURRENT flag is set.

Versions

I am using oracle javaSe-11 with jdk-11.0.2.

The CONCURRENT characteristic is defined as:

Characteristic value signifying that the element source may be safely concurrently modified (allowing additions, replacements, and/or removals) by multiple threads without external synchronization.

whereas the documentation of ArrayList says:

Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, …

It can't be said clearer that an ArrayList as a Stream source is everything but CONCURRENT .

The documentation you have cited does not contradict that. But I have to admit, it would be much better if there was a paragraph break before “For well-behaved stream sources, …”, to give the reader a break and reflect what has been said before it, as what comes then, is a different point, which applies to ArrayList , as well as all other “well-behaved stream sources”, but has no relevance to the CONCURRENT characteristic anymore and doesn't affect the constraints of behavioral parameters described before it.

All that new point says, is, that you may change an ArrayList before the Stream's terminal operation has been commenced, but still from only one thread (or with you own synchronization), but you still are not allowed to perform structural modifications during an ongoing terminal operation, which precludes any structural modifications from behavioral parameters, as these are always evaluated during an ongoing terminal operation.

The case of CopyOnWriteArrayList is different, it won't have the CONCURRENT characteristic, because its spliterators will have the IMMUTABLE characteristic instead, as you will be iterating over an immutable snapshot; modifications to the original CopyOnWriteArrayList will not affect the Stream.

CopyOnWriteArrayList : From the name it is evident that for each write a fresh copy is made. ConcurrentLinkedQueue : Concurrent write allowed using a array of Lock objects

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM