Блог

  • Многопоточность и виртуальные потоки

    Spring framework очень большая штука и пришлось потратить полдня, чтобы изучить сторону с @Async выполнением и виртуальными потоками.

    Чтобы у нас не терялась трассировка и контекст при выполнении кода в отдельных потоках необходимо задать отдельную, простую конфигурацию.

    Вот целиком конфигурация

    @Configuration
    public class AsyncConfig {
        @Bean
        public ContextSnapshotFactory contextSnapshotFactory() {
            return ContextSnapshotFactory.builder().build();
        }
    
        @Bean(name = TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)
        public AsyncTaskExecutor applicationTaskExecutor(ContextSnapshotFactory contextSnapshotFactory) {
            ThreadFactory virtualThreadFactory = Thread.ofVirtual()
                    .name("async-vt-", 0)
                    .factory();
            ExecutorService virtualExecutor = Executors.newThreadPerTaskExecutor(virtualThreadFactory);
    
            Executor decoratedExecutor = ContextExecutorService.wrap(
                    virtualExecutor,
                    contextSnapshotFactory::captureAll
            );
            return new TaskExecutorAdapter(decoratedExecutor);
        }
    
        @Bean(name="virtualThreadsParallelExecutor", destroyMethod = "close")
        public ExecutorService parallelExecutor(ContextSnapshotFactory contextSnapshotFactory) {
            ThreadFactory virtualThreadFactory = Thread.ofVirtual()
                    .name("parallel-custom-vt-", 0)
                    .factory();
    
            ExecutorService virtualExecutor = Executors.newThreadPerTaskExecutor(virtualThreadFactory);
    
            return ContextExecutorService.wrap(
                    virtualExecutor,
                    contextSnapshotFactory::captureAll
            );
        }
    }

    ContextSnapshotFactory тут то, что будет заполнять контекст трассировки и прочего в новом потоке.

    virtualThreadsParallelExecutor — кастомный экзекьютор, который можно инжектить в код. Удобно, не нужно обвесы делать.

    AsyncTaskExecutor — экзекьютор, который будет выполнять код методов под аннотацией @Async

  • Музыка кода бесконечна.

    Мой локальный дневник разработчика, куда я буду записывать опыт и факапы накопленные за 30 лет разработки. Коменты по умолчанию закрыты, ни с кем обсуждать ничего не буду. Политика строго под запретом.