Подтвердить что ты не робот

Может ли Java 8 `Stream` быть параллельным, даже если вы даже не просите об этом?

Как я вижу, очевидный код при использовании Java 8 Stream s, будь то потоки "объекта" или примитивные потоки (т.е. IntStream и друзья), будет просто использовать:

someStreamableResource.stream().whatever()

Но тогда у многих "потоковых ресурсов" также есть .parallelStream().

Что неясно при чтении javadoc, является ли поток .stream() всегда последовательным, а потоки потока .parallelStream() всегда параллельны...

И тогда есть Spliterator, и в частности его .characteristics(), один из которых заключается в том, что он может быть CONCURRENT или даже IMMUTABLE.

Чувство моего чувства заключается в том, что на самом деле, независимо от того, является ли Stream или нет, параллельным по умолчанию или параллельным вообще, руководствуется его базовым Spliterator...

Я на правильном пути? Я прочитал и прочитал снова, javadocs, и до сих пор не могу найти четкого ответа на этот вопрос...

4b9b3361

Ответ 1

Во-первых, через объектив спецификации. Независимо от того, является ли поток параллельным или последовательным, является частью состояния потока. Методы создания потока должны указывать, создают ли они последовательный или параллельный поток (и большинство в JDK do), но от них не требуется говорить об этом. Если источник потока не говорит, не предполагайте. Если кто-то передает вам поток, не предполагайте.

Параллельным потокам разрешено возвращаться к последовательному по своему усмотрению (поскольку последовательная реализация представляет собой параллельную реализацию, просто потенциально несовершенную); напротив, неверно.

Теперь, через призму реализации. В методах создания потока в коллекциях и других классах JDK мы придерживаемся дисциплины "создать последовательный поток, если пользователь явно не запрашивает parallelism". (Другие библиотеки, однако, делают разные варианты. Если они вежливы, они будут определять их поведение.)

Связь между потоком parallelism и Spliterator только идет в одном направлении. Разделитель может отказаться от разделения - фактически отрицая любой parallelism, но он не может требовать, чтобы клиент разделил его. Таким образом, несовместимый Spliterator может подорвать parallelism, но не определять его.

Ответ 2

API нечего сказать по этому поводу:

Потоки создаются с первоначальным выбором последовательных или параллельных выполнение. (Например, Collection.stream() создает последовательный поток, а Collection.parallelStream() создает параллельную.)

Что касается вашей линии рассуждений о том, что некоторые промежуточные операции могут быть потокобезопасными, вам может потребоваться прочитать сводку . В сводке пакетов обсуждаются промежуточные операции, состояние с отсутствием состояния и отсутствие правильного использования Stream на некоторой глубине.

Побочные эффекты в поведенческих параметрах для операций потока в общие, обескураженные, поскольку они часто могут приводить к невольным нарушениям требования о безгражданстве, а также другой безопасности потоков опасности.

Поведенческие параметры - это аргументы, предоставленные промежуточным операциям без состояния.

API не может делать какие-либо предположения

API может сделать любое предположение, которое он пожелает. Ответственность за эти допущения лежит на пользователе API. Однако предположения могут ограничивать юзабилити. API Stream препятствует созданию промежуточной промежуточной операции без сохранения состояния, которая не является потокобезопасной. Поскольку это запрещено, а не запрещено, большинство Stream будут последовательно "по умолчанию".

Ответ 3

Ну, ответьте на себя...

Подумав об этом чуть более серьезно (пойдите фигурой, такие вещи случаются только после того, как я действительно задаю вопрос), я действительно придумал причину, почему...

Промежуточные операции могут НЕ быть потокобезопасными; как таковой, API не может делать никаких предположений, поэтому, если пользователь хочет параллельный поток, он должен явно запросить его и убедиться, что все промежуточные операции, используемые в потоке, являются потокобезопасными.

Однако существует несколько вводящий в заблуждение случай Collector s; поскольку Collector не может заранее знать, будет ли он вызван как терминальная операция в потоке, который является параллельным или нет, контракт дает понять, что "просто для того, чтобы быть в безопасности", любой Collector должен быть потокобезопасным.

Ответ 4

Здесь упоминается здесь: "Когда вы создаете поток, он всегда является последовательным потоком, если не указано иное" . И здесь: "Допустимо для этого метода (parallelStream) возвращать последовательный поток" .

CONCURRENT и IMMUTABLE не связаны (напрямую) с этим. Они определяют, может ли базовая коллекция быть изменена, не приводя к тому, что разделитель недействителен или является неизменным соответственно. Особенностью spliterator, которая в значительной степени определяет поведение parallelStream, является trySplit. Операции с терминалами в параллельном потоке будут в конечном итоге вызывать trySplit, и вся эта реализация в конце дня определит, какие части, если они есть, обрабатываются параллельно.

Ответ 5

Это приложение не ограничено спецификацией прямо сейчас, однако короткий ответ НЕТ. Существуют функции parallelStream() и stream(), но это просто предоставляет вам способы доступа к параллельной или последовательной реализации общих основных операций для обработки потока. В настоящее время среда выполнения не может предположить, что ваши операции являются потокобезопасными без явного использования вызова parallelStream() или parallel(), тогда реализация по умолчанию stream() должна иметь последовательное поведение.