首页 > 解决方案 > @Async 指定的执行器是否适用于 CompletableFuture.supplyAsync(supplier)?

问题描述

我有一个执行人,

@Bean("someExecutor")
public Executor someExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(2);
    executor.setMaxPoolSize(2);
    executor.setQueueCapacity(500);
    executor.setThreadNamePrefix("AsyncMethod-");
    executor.initialize();
    return executor;
}

和一个异步方法。

@Async("someExecutor")
public Future<List<String>> someMethod(){
    return CompletableFuture.supplyAsync(() -> {
        //long time job
        return listGeneratedByLongTimeJob;
    });
}

Spring 会为 someMethod 使用 someExecutor 吗?如何?

我知道supplierAsync(supplier)的一个重载方法是supplierAsync(supplier, executor),下面的代码怎么样?

@Autowired("someExecutor")
private Executor executor;

@Async()
public Future<List<String>> someMethod(){
    return CompletableFuture.supplyAsync(() -> {
        //long time job
        return listGeneratedByLongTimeJob;
    }, executor);
}

谢谢。

标签: javaspringspring-boot

解决方案


好吧,这需要一段时间才能弄清楚,在进入两个场景之前,我们需要讨论一下ForkJoinPool

来自 java.util.concurrent.CompletableFuture 文档

所有没有显式 Executor 参数的异步方法都使用 ForkJoinPool.commonPool()执行(除非它不支持至少两个并行级别,在这种情况下,会创建一个新线程来运行每个任务)。为了简化监控、调试和跟踪,所有生成的异步任务都是标记接口 CompletableFuture.AsynchronousCompletionTask 的实例。

因此,当您每次调用时CompletableFuture.supplyAsync(Supplier s),供应商将由ForkJoinPool线程执行,现在让我们开始案例 1

情况1:

为了清楚起见,我添加了一些sysout语句来打印线程名称

@Async("someExecutor")
public Future<String> asyncService() {
    System.out.println();

    System.out.println(Thread.currentThread().getName()+" - "+Thread.currentThread().getThreadGroup());

    System.out.println();
    return CompletableFuture.supplyAsync(()->{

    System.out.println(Thread.currentThread().getName()+" - "+Thread.currentThread().getThreadGroup());
        return "hello";
    });

}

输出:

AsyncMethod-1 - java.lang.ThreadGroup[name=main,maxpri=10]

ForkJoinPool.commonPool-worker-1 - java.lang.ThreadGroup[name=main,maxpri=10]

在这种情况下asyncService(),由AsyncMethod-1线程执行,供应商 insupplyAsync()ForkJoinPool

案例2:

@Autowired
private Executor someExecutor;


@Async
public Future<String> asyncService() {
    System.out.println();

    System.out.println(Thread.currentThread().getName()+" - "+Thread.currentThread().getThreadGroup());

    System.out.println();
    return CompletableFuture.supplyAsync(()->{

    System.out.println(Thread.currentThread().getName()+" - "+Thread.currentThread().getThreadGroup());
        return "hello";
    },someExecutor);

}

输出:

AsyncMethod-1 - java.lang.ThreadGroup[name=main,maxpri=10]

AsyncMethod-2 - java.lang.ThreadGroup[name=main,maxpri=10]

在第二种情况下asyncService(),方法和供应商supplyAsync()都使用来自someExecutor pool

默认情况下,Spring 使用 SimpleAsyncTaskExecutor 来实际运行这些方法,但我们在 config using docsasync中覆盖了它someExecutor@EnableAsync

默认情况下,Spring 将搜索关联的线程池定义:要么是上下文中唯一的 TaskExecutor bean,要么是名为“taskExecutor”的 Executor bean。如果两者都无法解析,则将使用 SimpleAsyncTaskExecutor 来处理异步方法调用。

注意:如果您没有@EnableAsync配置类,您将得到不同的结果,我将在 gitHub 中上传此代码并在此处添加链接


推荐阅读