哪些流操作使用 `CONCURRENT`、`IMMUTABLE` 和 `NONNULL` Spliterator 特性?
Which stream operations use `CONCURRENT`,`IMMUTABLE` and `NONNULL` Spliterator characteristics?
哪些流操作使用 CONCURRENT
、IMMUTABLE
和 NONNULL
Spliterator 特性?他们每个人如何帮助这些行动?
我不是在问那些标志是什么,这可以在文档中轻松找到。我在问哪些操作使用它们以及如何使用它们。
在Java8中,流操作没有使用这3个特性。这可以通过在 Java 来源中搜索这些常量来检查。
但是,当您编写自己的集合时,CONCURRENT
特性可能会影响并行流的行为。如果您从集合创建 Spliterator
并且 不 报告 CONCURRENT
特征,则拆分器将另外具有 SIZED
和 SUBSIZED
特征:
Collection<Integer> col = ...
Spliterator<Integer> s = Spliterators.spliterator(col, 0);
System.out.println(s.hasCharacteristics(Spliterator.SIZED)); // Prints true
System.out.println(s.hasCharacteristics(Spliterator.SUBSIZED)); // Prints true
但是如果你报告 CONCURRENT
特性,那么拆分器就不再是 SIZED
:
Collection<Integer> col = ...
Spliterator<Integer> s = Spliterators.spliterator(col, Spliterator.CONCURRENT);
System.out.println(s.hasCharacteristics(Spliterator.SIZED)); // Prints false
System.out.println(s.hasCharacteristics(Spliterator.SUBSIZED)); // Prints false
不是 SIZED
和 SUBSIZED
的拆分器并行化很差,因此当您编写自己的并发集合时,最好编写自定义拆分器而不是依赖默认拆分器实现。
首先要明确区分,你这里问的Spliterator
特性和这些依赖于Stream的source;因为还有(例如 CONCURRENT
、UNORDERED
和 IDENTITY_FINISH
for Collectors
)。
StreamOpFlag
中有评论说:
// The following Spliterator characteristics are not currently used but a
// gap in the bit set is deliberately retained to enable corresponding
// stream flags if//when required without modification to other flag values.
//
// 4, 0x00000100 NONNULL(4, ...
// 5, 0x00000400 IMMUTABLE(5, ...
// 6, 0x00001000 CONCURRENT(6, ...
// 7, 0x00004000 SUBSIZED(7, ...
据我了解,这些并不是与 Spliterator 中的直接一对一映射,但仍未使用。
目前(我已经搜索了 jdk-8 和 9 来源),两者都没有被利用 - 但仍然被 Spliterators 的一些实现所报告(例如,Arrays
报告 IMMUTABLE
和 ConcurrentHashMap
报告 NONNULL
)。
另一方面,这些标志可以在将来使用 - 如果您知道源不能包含空元素 (NONNULL
),显然您可以跳过一些空检查或定义 一些状态 为空。我想不出 CONCURRENT
或 IMMUTABLE
的任何示例,但可能有这样的示例。
例如,在 UNORDERED
和 CONCURRENT
收集器(!= Spliterator
属性)的当前实现下,当您执行 toConcurrentMap
。例如:
Set.of("one", "two", "das", "dasda")
.stream()
.parallel()
.collect(Collectors.toConcurrentMap(Function.identity(), String::length));
不会调用 combiner
- 因为没有必要。
可以针对您提到的 3 个特征中的任何一个进行此类优化。例如,您可以阅读 this,其中 StreamOpFlag.ORDERED
在 java 8 与 java 9
中更改了 findFirst
的结果
人们说 IMMUTABLE
没有被使用,但事实证明,Stream#iterate
报告 IMMUTABLE
:
jshell> Stream.iterate(0, i -> i + 1).spliterator().characteristics()
==> 1040
1040 是 IMMUTABLE | ORDERED
但看起来任何操作都会掉落 IMMUTABLE
(使用 map
、filter
、flatMap
、limit
进行测试, skip
;在 Java 16)
上测试
IntStream#iterate
、LongStream#iterate
和 DoubleStream#iterate
也报告 NONNULL
,但下一个操作也会将其删除。
哪些流操作使用 CONCURRENT
、IMMUTABLE
和 NONNULL
Spliterator 特性?他们每个人如何帮助这些行动?
我不是在问那些标志是什么,这可以在文档中轻松找到。我在问哪些操作使用它们以及如何使用它们。
在Java8中,流操作没有使用这3个特性。这可以通过在 Java 来源中搜索这些常量来检查。
但是,当您编写自己的集合时,CONCURRENT
特性可能会影响并行流的行为。如果您从集合创建 Spliterator
并且 不 报告 CONCURRENT
特征,则拆分器将另外具有 SIZED
和 SUBSIZED
特征:
Collection<Integer> col = ...
Spliterator<Integer> s = Spliterators.spliterator(col, 0);
System.out.println(s.hasCharacteristics(Spliterator.SIZED)); // Prints true
System.out.println(s.hasCharacteristics(Spliterator.SUBSIZED)); // Prints true
但是如果你报告 CONCURRENT
特性,那么拆分器就不再是 SIZED
:
Collection<Integer> col = ...
Spliterator<Integer> s = Spliterators.spliterator(col, Spliterator.CONCURRENT);
System.out.println(s.hasCharacteristics(Spliterator.SIZED)); // Prints false
System.out.println(s.hasCharacteristics(Spliterator.SUBSIZED)); // Prints false
不是 SIZED
和 SUBSIZED
的拆分器并行化很差,因此当您编写自己的并发集合时,最好编写自定义拆分器而不是依赖默认拆分器实现。
首先要明确区分,你这里问的Spliterator
特性和这些依赖于Stream的source;因为还有(例如 CONCURRENT
、UNORDERED
和 IDENTITY_FINISH
for Collectors
)。
StreamOpFlag
中有评论说:
// The following Spliterator characteristics are not currently used but a
// gap in the bit set is deliberately retained to enable corresponding
// stream flags if//when required without modification to other flag values.
//
// 4, 0x00000100 NONNULL(4, ...
// 5, 0x00000400 IMMUTABLE(5, ...
// 6, 0x00001000 CONCURRENT(6, ...
// 7, 0x00004000 SUBSIZED(7, ...
据我了解,这些并不是与 Spliterator 中的直接一对一映射,但仍未使用。
目前(我已经搜索了 jdk-8 和 9 来源),两者都没有被利用 - 但仍然被 Spliterators 的一些实现所报告(例如,Arrays
报告 IMMUTABLE
和 ConcurrentHashMap
报告 NONNULL
)。
另一方面,这些标志可以在将来使用 - 如果您知道源不能包含空元素 (NONNULL
),显然您可以跳过一些空检查或定义 一些状态 为空。我想不出 CONCURRENT
或 IMMUTABLE
的任何示例,但可能有这样的示例。
例如,在 UNORDERED
和 CONCURRENT
收集器(!= Spliterator
属性)的当前实现下,当您执行 toConcurrentMap
。例如:
Set.of("one", "two", "das", "dasda")
.stream()
.parallel()
.collect(Collectors.toConcurrentMap(Function.identity(), String::length));
不会调用 combiner
- 因为没有必要。
可以针对您提到的 3 个特征中的任何一个进行此类优化。例如,您可以阅读 this,其中 StreamOpFlag.ORDERED
在 java 8 与 java 9
findFirst
的结果
人们说 IMMUTABLE
没有被使用,但事实证明,Stream#iterate
报告 IMMUTABLE
:
jshell> Stream.iterate(0, i -> i + 1).spliterator().characteristics()
==> 1040
1040 是 IMMUTABLE | ORDERED
但看起来任何操作都会掉落 IMMUTABLE
(使用 map
、filter
、flatMap
、limit
进行测试, skip
;在 Java 16)
上测试
IntStream#iterate
、LongStream#iterate
和 DoubleStream#iterate
也报告 NONNULL
,但下一个操作也会将其删除。