Несколько месяцев назад, когда я присутствовал на Конференции Devoxx’18 в Антверпене, Бельгия, одной из самых захватывающих тем, которую я с нетерпением ждал, были Fibers от Project Loom. Волокна — это облегченные потоки пользовательского режима, запланированные средой выполнения JVM, а не операционной системой. Таким образом, они имеют очень низкие следы. Это означает отсутствие потенциально дорогостоящих переключений контекста — или, по крайней мере, переключений контекста под управлением Java VM. Усилия по волокну управляются проектной группой под названием Project Loom в рамках OpenJDK. Наконец, пару месяцев спустя у меня появилась возможность поиграться с Fibers. Планируется, что эта функция будет выпущена в следующих выпусках Java (исходный код, который я недавно проверил, был ответвлением JDK 13 — jdk-13-ea, поэтому я предполагаю, что текущий план — это 13-й основной выпуск Java — или более поздний) .

Первое понятие, которое мы посетим, — это Продолжения. Задачи Fiber заключены в Continuations и завершаются выполнением, как только для них вызывается метод yield(). Продолжения представляют собой состояние программы, которое можно приостановить или возобновить, они могут даже возвращать значение. Эта концепция уже существует в таких языках программирования, как Python, Go, Scheme, Haskell и т. д., или торгуется под другим названием, то есть «сопрограммами», которые, по сути, являются волокнами без планировщика.

Волокна = продолжение + планировщик

Задачи Java Fiber, заключенные в продолжения, будут выполняться потоками-носителями. Очевидно, что не гарантируется, что все волокна в программе будут выполняться одним и тем же потоком-носителем.

Чтобы протестировать Fibers на своей машине, сначала вам нужно проверить исходный код здесь. После выбора JDK в проекте вам необходимо добавить флаг виртуальной машины - -enable-preview в команду java, а также javac, чтобы включить функции предварительного просмотра перед компиляцией и/или запуском программы.

Давайте быстро взглянем на наш первый пример для Continuations. В приведенной ниже простой Java-программе, пока цикл for выполняет итерацию по списку букв, выполнение завершается, поэтому основной поток продолжается со строки 21. линия с циклом while. В этом случае мы сначала проверяем, выполнено ли продолжение, если это не так, выполнение возобновляется с строки 17:

Ниже вы видите вывод программы. Однако продолжение выполняется основным потоком. Состояние программы было только что оставлено в строке 17 и продолжено в строке 21, а возобновлено с строки 17 с помощью run() снова вызвать экземпляр продолжения:

Я упомянул, что волокна завернуты в продолжения. В следующем примере это похоже на демонстрацию продолжения, производитель, который запланирован как Fiber, помещает некоторые числа в очередь, из которой берет другой Fiber. Операции take() и put() в очереди блокируются, а емкость синхронизированной очереди равна нулю. Оба экземпляра Fiber синхронизируются в этом экземпляре синхронной очереди SynchronousQueue:

Вы можете увидеть пинг-понг между производителем и потребителем в потоке-носителе, который называется Fiber:

Как только поток блокируется в строке 22, поскольку операция размещения в очереди является блокирующей, цикл while завершает свое выполнение. Тем не менее, несущая нить не блокируется. Сразу же он выбирает другое волокно, которое является потребителем в примере, и запускает его. К счастью, потребитель приостанавливается и ждет там, а затем пытается извлечь элемент из очереди, что приводит к возобновлению выполнения в поставщике Fiber.

Заворачивать

Работа над Fibers/Continuations продолжается, и ожидаются серьезные обновления интерфейсов, а также их реализации. Более того, в текущем прототипе все еще есть некоторые ограничения, о которых Алан упомянул в своем разговоре. Если ваше приложение реализовано блокирующим образом, оно включает в себя множество блокирующих операций ввода-вывода, волокна могут стать для вас лекарством. Тем не менее, предстоит пройти долгий путь, поскольку Thread API распространяется по всей экосистеме Java, и я считаю, что интеграция Fibers без нарушения существующих API будет сложной задачей.

Кстати, если вы хотите узнать больше о волокнах и их ограничениях, могу порекомендовать доклад Алана Бейтмана на конференции Devoxx’18. Кроме того, в настоящее время я работаю над некоторыми тестами, чтобы сравнить производительность волокон с потоками Java, которые я планирую опубликовать здесь очень скоро.

Быть в курсе.