Исполнитель на виртуальных потоках в Java
Ручной перебор Thread.startVirtualThread в цикле
быстро разрастается: нужно собирать ссылки, ждать
завершения, обрабатывать ошибки. Для пачки однотипных
задач удобнее ExecutorService из
java.util.concurrent.
С Java 21 фабрика Executors даёт метод
newVirtualThreadPerTaskExecutor. Каждый
вызов submit или execute получает
свой виртуальный поток, после задачи он завершается.
Отдельный пул с фиксированным числом платформенных
рабочих для такого сценария не настраивают.
Несколько задач и ожидание через shutdown
и awaitTermination:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws InterruptedException {
try (ExecutorService exec = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 1; i <= 3; i++) {
int id = i;
exec.submit(() -> System.out.println("task " + id));
}
}
System.out.println("all finished");
}
}
Блок try-with-resources вызывает close
у исполнителя: новые задачи не принимаются, программа
дожидается текущих. Строка all finished
появится после всех task ….
Если нужен результат, используют submit с
Callable и Future.get или
ExecutorService.invokeAll. Смысл тот же:
каждая единица работы крутится на своём виртуальном
потоке, а платформенных носителей JVM держит мало.
Отправьте пять задач на виртуальных потоках, каждая печатает свой номер.
Закройте исполнитель и убедитесь, что после
close в консоли есть "ok".