Создание виртуальных потоков
Thread.ofVirtual и исполнители
«Создание виртуальных потоков» — бесплатный урок Java Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Способы создания виртуальных потоков
В Java есть несколько способов создания виртуальных потоков. Два наиболее важных — это построитель Thread.ofVirtual() и фабрика Executors.newVirtualThreadPerTaskExecutor().
В этом уроке вы разберёте каждый из них.
Построитель: start
Thread.ofVirtual() возвращает построитель. Вызов .start(runnable) создаёт и немедленно запускает поток.
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.ofVirtual().start(() ->
System.out.println("Started directly"));
t.join();
}
}Построитель: unstarted
Используйте .unstarted(runnable), если хотите настроить поток и запустить его позже.
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.ofVirtual().unstarted(() ->
System.out.println("Started later"));
System.out.println("Before start, alive? " + t.isAlive());
t.start();
t.join();
}
}Многоразовая фабрика
Построитель может создавать ThreadFactory с помощью .factory(). Каждый вызов newThread создаёт новый виртуальный поток.
import java.util.concurrent.ThreadFactory;
public class Main {
public static void main(String[] args) throws InterruptedException {
ThreadFactory factory = Thread.ofVirtual().name("job-", 0).factory();
Thread a = factory.newThread(() ->
System.out.println(Thread.currentThread().getName()));
Thread b = factory.newThread(() ->
System.out.println(Thread.currentThread().getName()));
a.start(); b.start();
a.join(); b.join();
}
}Удобный метод
Thread.startVirtualThread(runnable) — это сокращённая запись для создания и запуска безымянного виртуального потока одним вызовом.
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.startVirtualThread(() ->
System.out.println("One-liner virtual thread"));
t.join();
}
}Подход с исполнителем
Для кода, организованного вокруг задач, предпочитайте Executors.newVirtualThreadPerTaskExecutor(). Он создаёт новый виртуальный поток для каждой переданной задачи.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
try (ExecutorService exec = Executors.newVirtualThreadPerTaskExecutor()) {
exec.submit(() -> System.out.println("task one"));
exec.submit(() -> System.out.println("task two"));
}
System.out.println("All tasks submitted and completed");
}
}Почему стоит использовать автоматическое закрытие ресурсов
Начиная с Java 19, ExecutorService реализует AutoCloseable. Закрытие исполнителя в блоке с автоматическим закрытием ресурсов ожидает завершения всех переданных задач.
Это обеспечивает корректное структурированное завершение работы без ручных вызовов shutdown и awaitTermination.
Передача множества задач
Исполнитель для каждой задачи легко справляется с огромным количеством задач. Каждая задача получает собственный виртуальный поток.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static void main(String[] args) {
AtomicInteger sum = new AtomicInteger();
try (ExecutorService exec = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 1; i <= 1000; i++) {
final int n = i;
exec.submit(() -> sum.addAndGet(n));
}
}
System.out.println("Sum 1..1000 = " + sum.get());
}
}Сбор результатов с помощью отложенного результата
submit возвращает объект Future, поэтому вы можете собирать возвращаемые значения так же, как и при работе с любым исполнителем.
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws Exception {
try (ExecutorService exec = Executors.newVirtualThreadPerTaskExecutor()) {
Future<Integer> f = exec.submit(() -> 6 * 7);
System.out.println("Result: " + f.get());
}
}
}Построитель или исполнитель
Выбирайте подход в зависимости от цели:
- Построитель / startVirtualThread для одноразовых потоков или настройки имён
- newVirtualThreadPerTaskExecutor для передачи исполнителю наборов задач и сбора результатов
Оба подхода создают по одному виртуальному потоку на каждую единицу работы — именно то, что нужно.
Никогда не кэшируйте виртуальный исполнитель
Не используйте один исполнитель виртуальных потоков так, словно это фиксированный пул рабочих потоков. Сам исполнитель можно повторно использовать, но помните: каждая задача порождает совершенно новый поток.
Суть в том, что в пул объединяются не потоки, а лишь обеспечивается удобная передача задач исполнителю.
Быстрая проверка
Выберите лучший способ запустить большую серию задач, каждую в собственном виртуальном потоке.
Итоги
Теперь вы знаете, как создавать виртуальные потоки:
Thread.ofVirtual().start(...)и.unstarted(...)- однострочная запись
Thread.startVirtualThread(...) .factory()для многоразовойThreadFactoryExecutors.newVirtualThreadPerTaskExecutor()с автоматическим закрытием ресурсов
Далее вы узнаете, как выбирать между платформенными и виртуальными потоками.
Часто задаваемые вопросы
Урок «Создание виртуальных потоков» бесплатный?
Да — полный текст урока «Создание виртуальных потоков» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Создание виртуальных потоков»?
Thread.ofVirtual и исполнители Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Создание виртуальных потоков»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Что такое виртуальные потоки
- Создание виртуальных потоков
- Платформенные и виртуальные потоки
- Ошибки: закрепление и ThreadLocals