Gymterview
senior

Чем отличаются корутины, Virtual Threads и Platform Threads?

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

Platform Threads (потоки платформы)

Обёртка над потоками ОС (kernel threads). Каждый Platform Thread = один поток ОС.

Пример
Thread thread = new Thread(() -> System.out.println("Platform Thread"));
thread.start();
  • Управляются планировщиком ОС (вытесняющее планирование)
  • Стек ~1 МБ (фиксированный)
  • Создание и переключение контекста дорогие
  • Лимит — тысячи потоков на JVM
  • Подходят для CPU-bound задач

Virtual Threads (Java 21)

Легковесные потоки, управляемые JVM. Модель M:N — множество виртуальных потоков на нескольких carrier threads.

Пример
Thread vThread = Thread.ofVirtual().start(() -> System.out.println("Virtual Thread"));
  • Управляются JVM (continuation-based)
  • Стек — несколько КБ, динамический рост (heap)
  • Создание и переключение — крайне дешёвые
  • Можно создать миллионы
  • При блокировке JVM «отсоединяет» от носителя
  • Полная совместимость с существующим API Thread
  • Подходят для IO-bound задач

Корутины (Kotlin Coroutines)

Конструкция уровня языка Kotlin (не JVM). Кооперативная многозадачность — приостановка в явных точках suspend.

Пример
suspend fun fetchData(): String {
    delay(1000) // Suspend point — НЕ блокирует поток
    return "данные"
}

fun main() = runBlocking {
    launch { println(fetchData()) }
}
  • Кооперативное планирование (приостановка только в suspend-функциях)
  • Structured Concurrency встроена с самого начала
  • Не являются потоками — это приостанавливаемые вычисления
  • Потребление — несколько сотен байт

Сравнительная таблица:

Характеристика Platform Thread Virtual Thread Корутина (Kotlin)
Уровень ОС JVM Язык (Kotlin)
Планирование Вытесняющее (ОС) Вытесняющее (JVM) Кооперативное
Стоимость создания ~1 мс ~1 мкс Очень низкая
Потребление памяти ~1 МБ ~несколько КБ ~сотни байт
Макс. количество Тысячи Миллионы Миллионы
Точки переключения Любое место Блокирующие операции Только suspend
Structured Concurrency Нет StructuredTaskScope (preview) Встроена
Совместимость с Java API Полная Полная Через адаптеры
CPU-bound Подходит Не лучше Platform Dispatchers.Default
IO-bound Не масштабируется Отлично Отлично

Когда что использовать:

Пример
// 1. CPU-bound → Platform Threads (ForkJoinPool)
ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
pool.submit(() -> heavyComputation());

// 2. IO-bound (Java) → Virtual Threads
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    executor.submit(() -> callExternalApi());
    executor.submit(() -> queryDatabase());
}
Пример
// 3. IO-bound (Kotlin) → Корутины
coroutineScope {
    async(Dispatchers.IO) { callExternalApi() }
    async(Dispatchers.IO) { queryDatabase() }
}

Как обрабатывается блокировка:

  • Virtual Thread: JVM автоматически unmount при блокирующем вызове, прозрачно для кода.
  • Корутина: блокировка только в suspend-точках; обычный блокирующий вызов заблокирует поток диспетчера.

Ключевые различия в философии:

  • Virtual Threads — используют существующий блокирующий API, JVM делает его неблокирующим «под капотом».
  • Корутины — новый синтаксис (suspend), больше контроля (диспетчеры, каналы), явные точки приостановки.
  • Kotlin-корутины могут работать поверх Virtual Threads, объединяя преимущества обоих.

Частые ошибки:

  • Virtual Threads для CPU-bound — не даёт преимущества.
  • Блокировка в корутинах вне Dispatchers.IO — голодание общего пула.
  • Замена всех Platform Threads на Virtual без анализа — pinning в synchronized.

Тренд 2024-2026: отказ от реактивных фреймворков (WebFlux, RxJava) в пользу Virtual Threads для новых проектов, где реактивность использовалась только ради масштабируемости IO.

Аналогия: Platform Thread — это курьер на автомобиле: дорогой, но выполняет любую работу. Virtual Thread — курьер на велосипеде: дешёвый, по городу (IO) быстрее, но тяжёлый груз (CPU) не потянет. Корутина — дрон: ещё легче, летает быстро, но требует специальную инфраструктуру (Kotlin runtime) и умеет приземляться только в отмеченных точках (suspend).

На собеседовании важно показать, что вы понимаете: это не конкурирующие, а взаимодополняющие технологии. Platform Threads — фундамент, Virtual Threads — масштабируемость IO в Java, корутины — экосистема Kotlin. Прямое сравнение производительности некорректно, так как они работают на разных уровнях.