Virtual threads (Java 21)
Тема дорожной карты · Java
Virtual Threads в Java — это лёгкие, управляемые JVM потоки, введённые как стабильная функция в Java 21 (JEP 444) через Project Loom, предназначенные для того, чтобы высококонкурентное I/O-ёмкое программирование стало столь же простым, как написание последовательного блокирующего кода без потери масштабируемости. В отличие от платформенных потоков — обёрток 1:1 вокруг дорогостоящих потоков ОС, ограниченных десятками тысяч на JVM-процесс, — Virtual Threads в Java являются объектами, выделяемыми в куче, планируемыми JVM на небольшой пул потоков-носителей платформы через ForkJoinPool, что позволяет создавать миллионы Virtual Threads с минимальными накладными расходами. Virtual Threads в Java создаются через Thread.ofVirtual().start(task), Thread.startVirtualThread(runnable) или Executors.newVirtualThreadPerTaskExecutor(), и прозрачно интегрируются с synchronized, ReentrantLock, JDBC, блокирующими операциями NIO и ThreadLocal — хотя закрепление (удержание потока-носителя во время synchronized или нативной блокировки) следует минимизировать, предпочитая ReentrantLock в коде с интенсивным использованием Virtual Threads. Spring Boot 3.2+ включает Virtual Threads для Tomcat, Jetty и выполнения @Async через единственное свойство (spring.threads.virtual.enabled=true), позволяя существующему блокирующему коду Spring MVC, Spring Data JPA и JDBC обслуживать высокую конкурентность запросов без переписывания в реактивном стиле. Virtual Threads в Java выполняют обещание Project Loom: структурированная конкурентность через StructuredTaskScope дополнительно упрощает паттерны ветвления, отмену и распространение ошибок, которые раньше требовали сложных цепочек CompletableFuture или реактивных операторов.
Как это работает
Virtual threads (Java 21) имеет много инструментов: Thread (низкоуровневый), Executor / ExecutorService (пулы потоков), CompletableFuture (async-композиция), Future, java.util.concurrent коллекции (ConcurrentHashMap, BlockingQueue, CopyOnWriteArrayList), атомарные примитивы (AtomicInteger, AtomicReference). Java 21 даёт virtual threads (Project Loom — миллионы лёгких потоков, идеально для I/O-bound). Синхронизация: synchronized, ReentrantLock, ReadWriteLock, StampedLock. Memory model (JMM) управляет видимостью.
Когда применять
ExecutorService вместо сырых Thread — пулы управляют жизненным циклом. CompletableFuture — для async-композиции (thenApply, thenCompose, allOf). На Java 21+ virtual threads делают блокирующий I/O практичным на высокой конкурентности (Executors.newVirtualThreadPerTaskExecutor()). ConcurrentHashMap — для shared-state. Прочтите "Java Concurrency in Practice" до серьёзного concurrent-кода.
Типичные ошибки
Ловушки Virtual threads (Java 21): shared mutable state без синхронизации (visibility-баги); volatile-"фикс" для race, требующих атомарности (volatile только видимость, не атомарный RMW); deadlock из-за двух локов в разном порядке; не daemon-threads когда нужно (JVM висит при shutdown); слишком много потоков для I/O-bound до Loom (новый ответ — virtual threads).