简体   繁体   中英

Stream ordered/unordered problems

I have the following code:

Set<Integer> l = new TreeSet<>();
l.add(1);
l.add(10);
l.add(3);
l.add(-3);
l.add(-4);

and I want to unorder the collection with:

l.stream().unordered().forEach(System.out::println);

but the forEach returns always the collection ordered!

Then I have also another doubt about the below sentence from here :

For sequential streams, the presence or absence of an encounter order does not affect performance, only determinism. If a stream is ordered, repeated execution of identical stream pipelines on an identical source will produce an identical result; if it is not ordered, repeated execution might produce different results.

In fact if I try this code on an unordered stream the results is always the same and never produce different results:

Arrays.stream( new int[]{8, -1, 3}).forEach(System.out::println);
Arrays.stream( new int[]{8, -1, 3}).forEach(System.out::println);

I really don't understand this API part...

The unordered() operation doesn't do any actions to explicitly unorder the stream. What it does is that it removes the constraint on the stream that it must remain ordered, thereby allowing subsequent operations to use optimizations that don't have to take ordering into consideration.

You can read about this in the Java 8 docs :

For sequential streams, the presence or absence of an encounter order does not affect performance, only determinism. If a stream is ordered, repeated execution of identical stream pipelines on an identical source will produce an identical result; if it is not ordered, repeated execution might produce different results.
For parallel streams, relaxing the ordering constraint can sometimes enable more efficient execution.
...

In cases where the stream has an encounter order, but the user does not particularly care about that encounter order, explicitly de-ordering the stream with unordered() may improve parallel performance for some stateful or terminal operations.

You are using a TreeSet, which orders the elements. So, the elements will be:

-4, -3, 1, 3, 10

Using a serial stream does not change the order, so the result is not dependent on the property of the stream of being ordered/unordered, as you can see in the first example "Serial Stream" (and as you noticed yourself).

l.stream().map(s->s+" ").forEach(System.out::print);

Result: -4 -3 1 3 10

l.stream().unordered().map(s->s+" ").forEach(System.out::print);

Result: -4 -3 1 3 10

If you make the stream parallel , then more than one thread can be created and the result is no longer guaranteed, because it depends on the specific execution. Note also that forEach() is not an ordered operation , meaning that it executes whenever it has something to process in its pipeline. See the example "Unordered Operations on a Parallel Stream":

l.stream().parallel().map(s->s+" ").forEach(System.out::print);

Result: 3 10 -3 1 -4

l.stream().unordered().map(s->s+" ").parallel().forEach(System.out::print);

Result: 3 -4 -3 1 10

Things change when you use Ordered Operations (like findFirst(), limit() and skip()) in a parallel stream. When you use findFirst() in a pipeline, what you really want is having the first element, according to the order of the elements in the stream, you just don't want any element, in which case you would be using findAny(). To have deterministic results by these operations, you lose the benefits of using a parallel stream, because the execution has to be serialized to process the elements in a specific order.

   l.stream().parallel().skip(2).limit(2).findFirst().ifPresent(System.out::print);

Result: 1 . This result will always be the same, no matter how many times you execute the code.

l.stream().unordered().parallel().skip(2).limit(2).findFirst().ifPresent(System.out::print);

Result: -3 . This result may (or may not) change every time you execute the code, because we specified that the order is not important.

Here is the complete code:

public static void main(String[] args) {
    Set<Integer> l = new TreeSet<>();
    l.add(1);
    l.add(10);
    l.add(3);
    l.add(-3);
    l.add(-4);

    System.out.println("Serial Stream");
    l.stream().map(s->s+" ").forEach(System.out::print);
    System.out.println();
    l.stream().unordered().map(s->s+" ").forEach(System.out::print);
    System.out.println("\n");

    System.out.println("Unordered Operations on a Parallel Stream");
    l.stream().parallel().map(s->s+" ").forEach(System.out::print);
    System.out.println();
    l.stream().unordered().map(s->s+" ").parallel().forEach(System.out::print);
    System.out.println("\n");

    System.out.println("Ordered Operations on a Parallel Stream");
    l.stream().parallel().skip(2).limit(2).findFirst().ifPresent(System.out::print);
    System.out.println();
    l.stream().unordered().parallel().skip(2).limit(2).findFirst().ifPresent(System.out::print);
    System.out.println("\n");

}

Serial Stream

-4 -3 1 3 10

-4 -3 1 3 10

Unordered Operations on a Parallel Stream

3 10 -3 -4 1

-3 1 3 10 -4

Ordered Operations on a Parallel Stream

1

-3

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