SpringBoot对异步任务的支持

异步方法

在配置类上配置 @EnableAsync 注解开启异步处理。

在方法上加上注解@Async将该方法标记为异步任务。

用法和FutureTask+Callable差不多,可以返回AsyncResult类型,它是Future的一个实现类。

例:

@Async
public Future<String> asyncTask() throws InterruptedException{
    Thread.sleep(2000);
    return new AsyncResult<>("任务完成");
}

异步线程池

如果一直使用@Async不配合线程池,会消耗很多资源,效率变低,Spring中有一个AsyncConfigurer接口,可以通过它配置线程池。

public interface AsyncConfigurer {

    //获取线程池
    @Nullable
    default Executor getAsyncExecutor() {
        return null;
    }

    //异步异常处理器
    @Nullable
    default AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return null;
    }
}

于是我们可以创建一个配置类,在这里面写实现,@EnableAsync 注解放到这个配置类上面可以增加可读性。

@Configuration
@Slf4j
public class AsyncConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        log.info("正在创建线程池");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(30);
        executor.setQueueCapacity(2000);
        executor.setThreadNamePrefix("global-thread-pool-");
        executor.initialize();
        return executor;
    }
}

这样创建的线程池是全局的,也就是说默认使用@Async标注的方法都会从这个线程池中取线程,我们可以测试一下:

@Async
public void testPool() throws InterruptedException {
    System.out.println(Thread.currentThread().getName());
    Thread.sleep(1000);
}

输出:

global-thread-pool-1

如果我们想让它灵活度更高一点,可以往IoC容器中注入一些Executor,使用@Async("")的value来指定一个要使用的线程池的bean名称。

例如,给配置类中添加注入Executor bean的方法:

@Configuration
@Slf4j
public class AsyncConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        log.info("正在创建线程池");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(30);
        executor.setQueueCapacity(2000);
        executor.setThreadNamePrefix("global-thread-pool-");
        executor.initialize();
        return executor;
    }

    @Bean("bigExecutor")
    public Executor getBigExecutor() {
        log.info("正在创建线程池");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(50);
        executor.setMaxPoolSize(80);
        executor.setQueueCapacity(80);
        executor.setThreadNamePrefix("big-thread-pool-");
        executor.initialize();
        return executor;
    }
}

指定使用线程池:

@Async("bigExecutor")
public void testBigPool() throws InterruptedException {
    System.out.println(Thread.currentThread().getName());
    Thread.sleep(1000);
}

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/springboot%e5%af%b9%e5%bc%82%e6%ad%a5%e4%bb%bb%e5%8a%a1%e7%9a%84%e6%94%af%e6%8c%81/