Комментарии 7
Крутая статья, спасибо!
Возник вопрос: если провести параллель с C++ - где у нас есть системные threads и примитивы синхронизации вроде mutex/condition_variable - то как виртуальные потоки в Java взаимодействуют с настоящими системными потоками под капотом?
Есть ли там какая-то «скрытая» синхронизация на уровне carrier-threads? Например, пулы, мьютексы, шедулинг очередей задач? Или виртуальный поток полностью избегает тяжёлых блокировок и переключается без участия ОС?
Есть carrier-threads(настоящий поток ОС), в котором может быть много виртуальных потоков.
Виртуальные потоки не держат стек в памяти ОС, их стек хранится в куче и выделяется динамически.
На уровне JVM есть планировщик виртуальных потоков. Он управляет тем, какой виртуальный поток монтировать на какой carrier-thread.
Планировщик использует FIFO-очередь (First-In-First-Out) для ожидания выполнения задач на carrier-thread.
Также же еще весь сок в том, что виртуальные потоки полностью совместимы со старым апи, то есть как раз и экзекуторы, симафоры и т.д)
Спасибо за комментарий, рад, что вам понравилась статья)
JVM старается свести к минимуму использование системных примитивов синхронизации. Они во-первых медленные, во-вторых плохо переносимые между платформами. Причем это верно и для виртуальных потоков, и для старых, «настоящих».
Есть низкоуровневый класс LockSupport, который предоставляет что-то вроде простенького семафора (park, unpark, parkNanos, …) и делегирует это ядру ОС. Он используется только после когда испробованы неблокирующие методы (барьеры, compare-and-swap), но все равно требуется настоящая блокировка. Все высокоуровневые ReentrantLock/BlockingQueue/итп завязаны на LockSupport и содержат кучу неблокирующего кода.
Парковать виртуальные потоки на уровне ОС нужно еще реже. Часто два виртуальных потока висят на одном настоящем, это легко проверяется. Если парковка все-таки нужна, виртуальный поток будет предварительно размонтирован (то есть освободит системный поток для других).
В JVM 24/25 наконец пофиксили баг с пиннингом synchronized, и вообще красота настала. Старый Jetty-сервер стал держать тысячи соединений, практически без изменения кода (только последний Jetty нужен)
Совершенно зря назвали их тоже потоками. Получается путаница, ведь в реальности виртуальный поток отличается от обычного почти так же, как поток от процесса (количестенно, не качественно).
Тем более, что когда есть поток поверх потока, то возникает ощущение, что можно и дальше наслаивать — поток поверх потока поверх потока, а это совсем не так.
Спасибо. Интересная статья.

Многопоточность для самых маленьких. Виртуальные потоки. Часть 2