Получение параллельного потока из коллекции

Правильно ли, что с Java 8 вам необходимо выполнить следующий код, чтобы получить параллельный поток из Collection?

private <E> void process(final Collection<E> collection) {
    Stream<E> stream = collection.parallelStream().parallel();
    //processing
}

Из API Collection:

по умолчанию Stream parallelStream()

Возвращает возможно параллельный поток с этой коллекцией в качестве источника. Для этого метода можно возвращать последовательный поток.

Из BaseStream API:

S parallel()

Возвращает эквивалентный поток, параллельный. Может вернуться сам, потому что поток уже параллелен, или потому, что базовое состояние потока было изменено на параллельное.

Неужели неудобно, что мне нужно вызвать функцию, которая предположительно параллелирует поток дважды?

Ответ 1

В основном реализация Collection.parallelStream() по умолчанию создает параллельный поток. Реализация выглядит следующим образом:

default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
}

Но это метод по умолчанию, для какого-то класса реализации совершенно справедливо предоставить другую реализацию для создания последовательного потока. Например, предположим, что я создаю SequentialArrayList:

class MySequentialArrayList extends ArrayList<String> {
    @Override
    public Stream<String> parallelStream() {
        return StreamSupport.stream(spliterator(), false);
    }
}

Для объекта этого класса следующий код напечатает false, как ожидалось:

ArrayList<String> arrayList = new MySequentialArrayList();
System.out.println(arrayList.parallelStream().isParallel());

В этом случае вызов метода BaseStream#parallel() гарантирует, что возвращенный поток всегда параллелен. Либо он уже был параллелен, либо параллелен, установив для поля parallel значение true:

public final S parallel() {
    sourceStage.parallel = true;
    return (S) this;
}

Это реализация метода AbstractPipeline#parallel().

Итак, следующий код для одного и того же объекта напечатает true:

System.out.println(arrayList.parallelStream().parallel().isParallel());

Но если поток уже параллелен, то да это дополнительный вызов метода, но это гарантирует, что вы всегда получите параллельный поток. Я еще не вникал в распараллеливание потоков, поэтому я не могу прокомментировать, какая коллекция или в каких случаях parallelStream() предоставит вам последовательный поток.