CompletableFuture的一个坑

正常是这样调用, 这个在正常调试时是没问题的.

1
2
3
CompletableFuture.runAsync(()->{
    xxx...
});

但是当进行打包后, 放到服务器上运行时, 就会出现 ClassNotFoundException.

镜像使用的是 ghcr.io/graalvm/graalvm-ce, 该镜像内部为Tomcat服务.

当在runnable 中调用mybatis的相关方法时, 就会报 ClassNotFoundException, 导致完全无法进行数据库操作.

经过搜索, 发现是默认的 CompletableFuture.runAsync 方法内部使用了 ForkJoinPool.commonPool() 方法, 这个线程池在Tomcat中就会出问题.

解决方案: 手动指定一个自己的线程池.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@EnableAsync
@Configuration
public class MyTaskExecutor {
    @Bean("threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(120);
        // 设置队列容量
        executor.setQueueCapacity(120);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(600);
        executor.setThreadNamePrefix("BM-Pool#Task");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

注入后作为runAsync的第二个参数即可.

Licensed under CC BY-NC-SA 4.0
记录平时瞎折腾遇到的各种问题, 方便查找
使用 Hugo 构建
主题 Stack 3.29.0Jimmy 设计