Рубрики
Без рубрики

Потоковые модели в Java

Краткий и практический обзор моделей потоковой передачи в Java.

Автор оригинала: Graham Cox.

1. введение

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

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

2. Собственные потоки

Стандартный способ реализации многозадачности в Java-использовать потоки . Потоковая передача обычно поддерживается вплоть до операционной системы. Мы называем потоки, которые работают на этом уровне, “собственными потоками”.

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

Стандартная модель потоковой передачи в Java, охватывающая все языки JVM, использует собственные потоки . Это было так с Java 1.2 и происходит независимо от базовой системы, на которой работает JVM.

Это означает, что каждый раз, когда мы используем любой из стандартных механизмов потоковой передачи в Java, мы используем собственные потоки. Это включает в себя java.lang.Поток , java.util.concurrent.Исполнитель , java.util.concurrent.ExecutorService и так далее.

3. Зеленые нити

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

Это звучит очень сложно, и это так. Но это осложнение, о котором нам, как правило, не нужно беспокоиться. Базовая архитектура заботится обо всем этом, и мы можем использовать ее, как если бы это была собственная потоковая модель.

Так зачем нам это делать? Собственные потоки очень эффективны для запуска, но они имеют высокую стоимость запуска и остановки. Зеленые потоки помогают избежать этих затрат и дают архитектуре гораздо большую гибкость. Если мы используем относительно длительные потоки, то собственные потоки очень эффективны. Для очень недолговечных рабочих мест стоимость их запуска может перевесить выгоду от их использования . В этих случаях зеленые нити могут стать более эффективными.

К сожалению, Java не имеет встроенной поддержки зеленых потоков.

Очень ранние версии использовали зеленые потоки вместо собственных потоков в качестве стандартной модели потоковой передачи. Это изменилось в Java 1.2, и с тех пор не было никакой поддержки для него на уровне JVM.

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

4. Волокна

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

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

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

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

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

В настоящее время Java не имеет встроенной поддержки волокон. Существуют некоторые библиотеки, которые могут внедрить это в наши приложения, включая, но не ограничиваясь:

4.1. Квазар

Квазар это библиотека Java, которая хорошо работает с чистой Java и Kotlin и имеет альтернативную версию, которая работает с Clojure.

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

Quasar также требует, чтобы Java 11 работала правильно, так что это может ограничить приложения, которые могут ее использовать. Более старые версии можно использовать на Java 8, но они не поддерживаются активно.

4.2. Килим

Kilim-это библиотека Java, которая предлагает очень похожую функциональность на Quasar, но делает это с помощью переплетения байт-кодов вместо агента Java . Это означает, что он может работать в большем количестве мест, но это усложняет процесс сборки.

Kilim работает с Java 7 и новее и будет работать правильно даже в сценариях, где агент Java не является опцией. Например, если другой уже используется для контрольно – измерительных приборов или мониторинга.

4.3. Проектный ткацкий станок

Project Loom -это эксперимент проекта OpenJDK по добавлению волокон в саму JVM, а не в качестве дополнительной библиотеки . Это даст нам преимущества волокон перед нитями. Реализуя его непосредственно в JVM, он может помочь избежать осложнений, которые могут возникнуть у агентов Java и байт-кода.

В настоящее время нет расписания выпуска Project Loom, но мы можем загрузить двоичные файлы раннего доступа прямо сейчас, чтобы посмотреть, как идут дела. Однако, поскольку это еще очень рано, мы должны быть осторожны, полагаясь на это для любого производственного кода.

5. Совместные процедуры

Сопрограммы являются альтернативой резьбе и волокнам. Мы можем думать о сопрограммах как о волокнах без какой-либо формы планирования . Вместо того, чтобы базовая система решала, какие задачи выполняются в любое время, наш код делает это напрямую.

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

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

6. Заключение

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