У меня есть собственная реализация AsyncTaskExecutor, которая использует виртуальные потоки для выполнения задач. Я использую здесь ThreadFactory, так как мне нужно завершить задачу для выполнения сквозных задач.
Поскольку VT являются потоками демонов, я думаю, что эти потоки будут продолжать работать в фоновом режиме в течение некоторого времени даже после остановки приложения.
Есть ли способ гарантировать, что все виртуальные потоки, созданные с помощью AsyncTaskExecutor, будут очищены до остановки приложения?
Асинктаскэкзекутор:
public class VirtualThreadTaskExecutor implements AsyncTaskExecutor {
private final ThreadFactory threadFactory;
public VirtualThreadTaskExecutor() {
this.threadFactory = Thread.ofVirtual().name("my-app-virtual-thread-", 0).factory();
}
@Override
public void execute(@NotNull Runnable task) {
var wrapped = MyTaskWrapper.wrap(task);
threadFactory.newThread(wrapped).start();
}
...
}
Бин:
@Bean
public AsyncTaskExecutor virtualThreadExecutor() {
return new VirtualThreadTaskExecutor();
}
Я считаю, что другой вариант — использовать SimpleAsyncTaskExecutor и setTaskTerminationTimeout, которые вызываются при вызове метода close().
Ваши рассуждения странны. Почему тот факт, что виртуальные потоки являются потоками-демонами, должен означать, что они будут работать в фоновом режиме дольше, чем потоки платформы? Кроме того, неясно, что вы имеете в виду под «очиститься до остановки приложения». Какую уборку вы имеете в виду?




Вместо определения пользовательского VirtualThreadTaskExecutor вы можете использовать TaskDecorator для работы с вашей wrap реализацией и в то же время использовать виртуальные потоки с SimpleAsyncTaskExecutor с setVirtualThreads конфигурацией, установленной как true. Наряду с этим, как вы указали, способ дождаться завершения задачи — это указать его явно с помощью setTaskTerminationTimeout.
@Bean для этого будет выглядеть так:
@Bean
public AsyncTaskExecutor virtualThreadTaskExecutor() {
SimpleAsyncTaskExecutor asyncTaskExecutor = new SimpleAsyncTaskExecutor();
asyncTaskExecutor.setVirtualThreads(true); // virtual threads enabled
asyncTaskExecutor.setTaskDecorator(MyTaskWrapper::wrap); // your custom wrapper
asyncTaskExecutor.setThreadFactory(Thread.ofVirtual().name("my-app-virtual-thread-", 0).factory());
asyncTaskExecutor.setTaskTerminationTimeout(5000); // ensure wait for task termination
return asyncTaskExecutor;
}
Редактировать:
(ссылка: Spring-boot-virtual-threads) Если для spring.threads.virtual.enabled установлено значение true, строка кода setVirtualThreads(true) неявно влияет на поведение методов, помеченных @EnableAsync.
В идеале Spring заботится о базовом жизненном цикле Executor. Но насколько я мог это проверить, вам в основном нужно было бы гарантировать, что завершение задачи учитывается во время завершения работы приложения для такого объявления, путем явного вызова его метода close() через перехватчик, такой как PreDestroy.
setTaskTerminationTimeout появится только после вызова метода close() в asyncTaskExecutor. Означает ли это, что я должен вызвать метод close в хуке жизненного цикла bean-компонента preDestroy?
@GovindaSakhare обновил аспект в ответе, в идеале Spring должен позаботиться о нем неявно, но, насколько я мог проверить (возможно, что-то упустил), вам придется явно вызывать close через крючок.
Можете ли вы также рассказать, что не так/сложно с
setTaskTerminationTimeoutв вашем случае?