Виртуальные потоки в Java
Сервис может одновременно ждать ответы от сотен клиентов: пока один запрос висит на сети, другой читает файл или ждёт строку из базы. Если под каждое ожидание заводить тяжёлый поток операционной системы, число потоков быстро упирается в лимиты, а память уходит на стеки и переключения контекста.
Виртуальный поток в Java 21 и новее это
обычный Thread с другим носителем: JVM
сама планирует его на небольшой пул платформенных
потоков. Пока задача блокируется на вводе или выводе,
носитель освобождается и может выполнять другой
виртуальный поток. Для кода задача по-прежнему
выглядит как отдельный поток со своим стеком.
В Java 27 виртуальные потоки уже часть стандартной модели конкурентности. Их не нужно включать флагами превью: достаточно JDK с поддержкой Loom. Платформенные потоки никуда не делись, они нужны там, где важна привязка к ядру или долгая работа без блокировок.
Проверить тип текущего потока можно через
Thread.currentThread().isVirtual(). Главный
поток программы остаётся платформенным, а фоновую
работу с ожиданиями часто удобнее отдавать виртуальным:
public class Main {
public static void main(String[] args) throws InterruptedException {
System.out.println("main virtual: " + Thread.currentThread().isVirtual());
Thread worker = Thread.startVirtualThread(() -> {
System.out.println("worker virtual: " + Thread.currentThread().isVirtual());
});
worker.join();
}
}
В выводе для main будет false, для
рабочего виртуального потока true. Дальше
разберём запуск, настройку имени, пул через
ExecutorService и типичные сценарии с
массовой блокирующей нагрузкой.