Означает ли спецификация, что операции над последовательными потоками Java должны оставаться в текущем потоке? - программирование
Подтвердить что ты не робот

Означает ли спецификация, что операции над последовательными потоками Java должны оставаться в текущем потоке?

Означает ли спецификация, что все операции над последовательными потоками Java выполняются в текущем потоке? (За исключением "forEach" и "forEachOrdered")

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

Я спрашиваю из-за ThreadLocals: я использую Framework, который использует ThreadLocals внутри. Даже простой вызов типа company.getName() в конечном итоге использует ThreadLocal. Я не могу изменить, как эта структура разработана. По крайней мере, не в разумные сроки.

Спецификация кажется запутанной здесь. В документации пакета "java.util.stream" указано:

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

...

Даже когда конвейер ограничен для получения результата, который согласуется с порядком встречи источника потока (например, IntStream.range(0,5).parallel(). Map (x → x * 2).toArray( ) должен производить [0, 2, 4, 6, 8]), никаких гарантий не делается относительно порядка, в котором функция сопоставления применяется к отдельным элементам, или в каком потоке выполняется какой-либо поведенческий параметр для данного элемента.

Я бы это интерпретировал так: Каждая операция в потоке может произойти в другом потоке. Но документация "forEach" и "forEachOrdered" явно заявляет:

Для любого данного элемента действие может выполняться в любое время и в любом потоке, который выбирает библиотека.

Это утверждение будет избыточным, если каждая операция потока может произойти в неуточненном потоке. Таким образом, верно противоположное: все операции над последовательным потоком гарантируются в текущем потоке, за исключением "forEach" и "forEachOrdered"?

У меня есть googled для авторитетного ответа о комбинации "Java", "Stream" и "ThreadLocal", но ничего не нашел. Близкое дело было ответом Брайана Гетца на связанный с этим вопрос здесь на Stack Overflow, но речь идет о порядке, а не о потоке, и речь идет только о "forEach", а не о других методах потока: Does Stream.forEach уважают определить порядок последовательных потоков?

4b9b3361

Ответ 1

Я считаю, что ответ, который вы ищете, не так четко определен, поскольку он будет зависеть от потребителя и/или разделителя и их характеристик:

Перед чтением главной цитаты:

https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#stream

default Stream stream() Возвращает последовательный поток с этой коллекцией в качестве источника. Этот метод следует переопределить, если метод spliterator() не может вернуть разделитель, который является IMMUTABLE, CONCURRENT или поздним связыванием. (Подробнее см. Раздел spliterator().)

https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html#binding

Несмотря на их очевидную полезность в параллельных алгоритмах, разветкители не должны быть потокобезопасными; вместо этого реализация параллельных алгоритмов с использованием разделителей должна обеспечивать, чтобы разделитель использовался только одним потоком за раз. Это, как правило, легко достигается с помощью последовательного ограничения потока, что часто является естественным следствием типичных параллельных алгоритмов, которые работают путем рекурсивного разложения. Нить, вызывающая trySplit(), может передать возвращенный Spliterator в другой поток, который, в свою очередь, может пересечь или разделить этот Spliterator. Поведение расщепления и обхода не определено, если два или более потока работают одновременно на одном и том же разделителе. Если исходная нить передает разделитель в другой поток для обработки, лучше всего, если эта передача обслуживания происходит до того, как любые элементы будут потребляться с помощью tryAdvance(), поскольку определенные гарантии (такие как точность оценкиSize() для SIZED-разделителей) действительны только до начала обхода.

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