Я посетил некоторую ИТ-конференцию и на сессии, посвященной функции виртуальных потоков в Java 21+ , было упомянуто, что synchronized
может (!) быть проблемой для виртуальных потоков из-за закрепления виртуального потока, и если это проблема - использование Замок может решить проблему.
Я не понимаю, почему Lock может быть лучше, чем синхронизироваться в контексте виртуальных потоков. Я предполагаю, что ReentrantLock может быть причиной того же закрепления. не так ли? Если нет – почему?
В принципе, нет причин, по которым synchronized
должен работать иначе, чем в простейшем варианте использования ReentrantLock
. Каким бы ни был подробный ответ, он будет следствием какого-то произвольного дизайнерского решения — возможно, какого-то решения, принятого давно. Что бы это ни было, ничто, кроме времени и денег, не могло бы помешать им это исправить.
Ваше чрезмерное использование жирного текста очень раздражает. Вы так разговариваете с людьми лицом к лицу? Вы выкрикиваете несколько слов в каждом предложении, которое произносите?
Возможный дубликат этого? Ответ хоть и старый, но благодаря своим изменениям содержит ссылку на виртуальные темы.
@Наман, тема, на которую ты ссылаешься, связана, но определенно не дублируется.
@VGR Я ожидал, что его легче читать, чем необработанный текст без кода. Не стесняйтесь редактировать - буду признателен
Причина проста: поддержка объектных мониторов — это изменение виртуальной машины более низкого уровня, тогда как ReentrantLock — это меньшая корректировка. Поэтому, скорее всего, приоритет был перенесен на более позднюю веху, чтобы сосредоточиться на других основных принципах. В недавней версии раннего доступа добавлена поддержка, поэтому эта проблема исчезнет в более позднем выпуске JDK.
Также связано с использованием синхронизации (System.out.println) внутри виртуальных потоков.
Виртуальные потоки ( волокна ) предназначены для задач, предполагающих блокировку , задач, которые не привязаны к процессору. К задачам блокировки относятся те, которые выполняют файловый ввод-вывод, ведение журнала, сетевые вызовы, доступ к базе данных и т. д.
Когда виртуальный поток заблокирован, его можно быстро переключить на другой виртуальный поток, чтобы сохранить занятость ядра ЦП. Быстрое переключение между виртуальными потоками делает их такими высокопроизводительными.
Текущая реализация в Java 21 и Java 22 имеет ограничение. Пока код внутри блока synchronized
выполняется, Java не может определить, заблокирован этот код или нет. Эту задачу нельзя отключить для выполнения другого виртуального потока. Таким образом, заблокированный код ничего не делает, кроме ожидания, и, следовательно, это ядро не выполняет никакой полезной работы.
Эта проблема зависания виртуального потока называется закреплением. Заблокированный виртуальный поток закрепляется за потоком хост-платформы на этом ядре. Закрепление противоречит цели использования виртуальных потоков.
Кратковременное закрепление не является проблемой. Например, быстрая проверка защищенной защитной переменной. Но проблема заключается в длительно работающем куске закрепленного кода. Такой долго выполняющийся фрагмент synchronized
кода не следует либо (а) запускать в виртуальном потоке, либо (б) следует переписать для использования ReentrantLock, а не synchronized
.
Команда Project Loom продолжает изучать этот вопрос. Решение находится в разработке. Таким образом, будущая версия Java может быть свободна от этого ограничения.
Кстати, аналогичная ситуация с закреплением и в нативном коде. Код Java, который использует JNI или Иностранные функции для вызова долго выполняющегося собственного кода, не должен использоваться в виртуальном потоке.
Чтобы понять виртуальные потоки:
Закрепление происходит только после входа в синхронизированный блок? А как насчет случая, когда поток заблокирован в ожидании освобождения синхронизированного блока монитора?
Это не отвечает на вопрос. В чем разница между синхронизированным и реентерабельным? Почему JVM может обнаружить операцию блокировки в одном, но не в другом? Ссылка на решение несколько полезна, но также не охватывает исходную проблему.
@Basilevs разница в том, что эта функция (переключение потока несущей на другой виртуальный поток) реализована для одного из них, но еще не реализована для другого. Но над реализацией для другого уже работают, как только это будет сделано, разницы уже не будет. В этом ответе все сказано.
ключевое слово Synchronized не приведет к созданию потока платформы, если оно заблокировано, в то время как другие реализации могут.