Почему ReentrantLock лучше для виртуальных потоков, чем для синхронизации?

Я посетил некоторую ИТ-конференцию и на сессии, посвященной функции виртуальных потоков в Java 21+ , было упомянуто, что synchronized может (!) быть проблемой для виртуальных потоков из-за закрепления виртуального потока, и если это проблема - использование Замок может решить проблему.

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

ключевое слово Synchronized не приведет к созданию потока платформы, если оно заблокировано, в то время как другие реализации могут.

ODDminus1 26.06.2024 12:53

В принципе, нет причин, по которым synchronized должен работать иначе, чем в простейшем варианте использования ReentrantLock. Каким бы ни был подробный ответ, он будет следствием какого-то произвольного дизайнерского решения — возможно, какого-то решения, принятого давно. Что бы это ни было, ничто, кроме времени и денег, не могло бы помешать им это исправить.

Solomon Slow 26.06.2024 13:11

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

VGR 26.06.2024 14:32

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

Naman 26.06.2024 14:36

@Наман, тема, на которую ты ссылаешься, связана, но определенно не дублируется.

gstackoverflow 26.06.2024 16:37

@VGR Я ожидал, что его легче читать, чем необработанный текст без кода. Не стесняйтесь редактировать - буду признателен

gstackoverflow 26.06.2024 16:38

Причина проста: поддержка объектных мониторов — это изменение виртуальной машины более низкого уровня, тогда как ReentrantLock — это меньшая корректировка. Поэтому, скорее всего, приоритет был перенесен на более позднюю веху, чтобы сосредоточиться на других основных принципах. В недавней версии раннего доступа добавлена ​​поддержка, поэтому эта проблема исчезнет в более позднем выпуске JDK.

Ben Manes 26.06.2024 17:53

Также связано с использованием синхронизации (System.out.println) внутри виртуальных потоков.

DuncG 28.06.2024 16:43
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
8
189
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

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

Текущая реализация в Java 21 и Java 22 имеет ограничение. Пока код внутри блока synchronized выполняется, Java не может определить, заблокирован этот код или нет. Эту задачу нельзя отключить для выполнения другого виртуального потока. Таким образом, заблокированный код ничего не делает, кроме ожидания, и, следовательно, это ядро ​​не выполняет никакой полезной работы.

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

Кратковременное закрепление не является проблемой. Например, быстрая проверка защищенной защитной переменной. Но проблема заключается в длительно работающем куске закрепленного кода. Такой долго выполняющийся фрагмент synchronized кода не следует либо (а) запускать в виртуальном потоке, либо (б) следует переписать для использования ReentrantLock, а не synchronized.

Команда Project Loom продолжает изучать этот вопрос. Решение находится в разработке. Таким образом, будущая версия Java может быть свободна от этого ограничения.

Кстати, аналогичная ситуация с закреплением и в нативном коде. Код Java, который использует JNI или Иностранные функции для вызова долго выполняющегося собственного кода, не должен использоваться в виртуальном потоке.

Чтобы понять виртуальные потоки:

  • Изучите JEP 444.
  • Посмотрите видеопрезентации Рона Пресслера, Алана Бейтмана и Хосе Помара.

Закрепление происходит только после входа в синхронизированный блок? А как насчет случая, когда поток заблокирован в ожидании освобождения синхронизированного блока монитора?

gstackoverflow 26.06.2024 18:25

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

Basilevs 28.06.2024 00:34

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

Holger 28.06.2024 12:29

Другие вопросы по теме