springboot使用@async实现异步线程池

1.介绍

工作中经常涉及异步任务,通常是使用多线程技术,比如线程池ThreadPoolExecutor,但使用Executors容易产生OOM,需要手动使用ThreadPoolExecutor创建线程池;在springboot使用 @async 可以实现异步调用,配置线程池参数,可以简单的实现多线程的线程池效果,从而简化开发,避免OOM;

2.异步调用,无返回结果

首先在启动类上加上@EnableAsync 注解

@SpringBootApplication
@EnableAsync
public class AsyncApplication {
    public static void main(String[] args) {
        SpringApplication.run(AsyncApplication.class,args);
    }
}

在函数上标上@sync注解,表示异步调用

@Async
public void exec2(){
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("exec2 执行完毕");
}
@GetMapping("exec2")
public String exec2(){
    mainService.exec2();
    return "exec2";
}

测试:浏览器立即返回结果,3秒之后后台才打印输出日志

2.异步调用,有返回值

@Async
public Future<String> exec3_1(){
    try {
        Thread.sleep(2500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("exec3_1 执行完毕");
    return new AsyncResult<>("exec3_1");
}

@Async
public Future<String> exec3_2(){
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("exec3_2 执行完毕");
    return new AsyncResult<>("exec3_2");
}
@GetMapping("exec3")
public String exec3() throws ExecutionException, InterruptedException {
    Future<String> exec3_1 = mainService.exec3_1();
    Future<String> exec3_2 = mainService.exec3_2();

    String result="";

    while (true){
        if(exec3_1.isDone() && exec3_2.isDone()){
            result=exec3_1.get()+"--"+exec3_2.get();
            break;
        }
    }
    return result;
}

测试:3秒后浏览器返回结果

4.线程池

在异步掉用中使用的@Async 注解,默认的线程池大小如下
# 核心线程数
spring.task.execution.pool.core-size=8  
# 最大线程数
spring.task.execution.pool.max-size=16
# 空闲线程存活时间
spring.task.execution.pool.keep-alive=60s
# 是否允许核心线程超时
spring.task.execution.pool.allow-core-thread-timeout=true
# 线程队列数量
spring.task.execution.pool.queue-capacity=100
# 线程关闭等待
spring.task.execution.shutdown.await-termination=false
spring.task.execution.shutdown.await-termination-period=
# 线程名称前缀
spring.task.execution.thread-name-prefix=task-

一般情况下,我们都需要手动创建线程池,使用 ThreadPoolTaskExecutor 类进行配置

@Configuration
public class PoolConfig {

    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(10);
        // 设置最大线程数
        executor.setMaxPoolSize(15);
        // 设置队列容量
        executor.setQueueCapacity(20);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix("zszxz-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}
原文地址:https://www.cnblogs.com/daikainan/p/14427162.html