欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring Boot异步任务:@Async

程序员文章站 2022-12-04 14:34:42
Spring Boot异步任务:@Async + 线程池...

介绍

  • 异步是相对于同步而言的,同步是指程序按预定顺序执行,每一步必须等到上一步完成后再执行,异步则无需等待上一步程序执行完即可执行。通常使用多线程来实现。

使用说明

1、引用依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<!-- web -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- 工具类,简化常用代码:get,set,toString等 -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.12</version>
			<optional>true</optional>
		</dependency>

2、线程池配置

application.properties

#***** thread *****
#线程池中线程的最少数量
thread.pool.corePoolSize=8
#线程池中线程的最大数量
thread.pool.maxPoolSize=16
#所允许的空闲时间
thread.pool.keepAliveSeconds=300
#等待队列的大小
thread.pool.queueCapacity=32
/**
 * 线程池配置
 * @author yanyuan
 */
@Data
@ConfigurationProperties(prefix = "thread.pool")
public class ThreadPoolConfig {
    private int corePoolSize;

    private int maxPoolSize;

    private int keepAliveSeconds;

    private int queueCapacity;
}

```java
/**
 * 创建线程池
 * EnableAsync 开启异步的支持
 * @Author yanyuan
 *
 */
@Configuration
@EnableAsync 
@EnableConfigurationProperties(ThreadPoolConfig.class)
public class TaskExecutePool {

    @Autowired
    private ThreadPoolConfig config;

    @Bean("taskAsyncPool")
    public Executor taskAsyncPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程池大小
        executor.setCorePoolSize(config.getCorePoolSize());
        //最大线程数
        executor.setMaxPoolSize(config.getMaxPoolSize());
        //队列容量
        executor.setQueueCapacity(config.getQueueCapacity());
        //活跃时间
        executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
        //线程名字前缀
        executor.setThreadNamePrefix("executor-");

        // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
        // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

3、异步任务方法

/**
 * @author: yanyuan
 * @Date: 2020/11/11 18:49
 * @Description: 异步任务
 */
@Component
@Slf4j
public class AsyncTask {

    public String doTask() throws InterruptedException {
        log.info("thread name = {}, message = {}",
                Thread.currentThread().getName(),
                "task start");
        //等待3秒
        TimeUnit.SECONDS.sleep(3);
        log.info("thread name = {}, message = {}",
                Thread.currentThread().getName(),
                "task end");
        return "task complete";
    }


    /**
     * Async 对某个方法进行异步执行
     * @return
     * @throws InterruptedException
     */
    @Async("taskAsyncPool")
    public Future<String> doAsyncTask() throws InterruptedException {
        log.info("thread name = {}, message = {}", Thread.currentThread().getName(), "async start");
        //等待3秒
        TimeUnit.SECONDS.sleep(3);
        log.info("thread name = {}, message = {}", Thread.currentThread().getName(), "async end");
        return new AsyncResult<>("async execute complete");
    }
}

4、Controller测试

/**
 * @author: yanyuan
 * @Date: 2020/11/11 19:24
 * @Description:
 */
@RestController
@Slf4j
public class TaskController {

    @Autowired
    AsyncTask asyncTask;

    @GetMapping("task")
    public String task() throws InterruptedException, ExecutionException {
        long times = System.currentTimeMillis();
        asyncTask.doTask();
        return "任务执行耗时:"+ (System.currentTimeMillis() - times) + "ms";
    }

    /**
     * 异步任务
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     */
    @GetMapping("async-task")
    public String asyncTask() throws InterruptedException, ExecutionException {
        long times = System.currentTimeMillis();
        asyncTask.doAsyncTask();
        return "任务执行耗时:"+ (System.currentTimeMillis() - times) + "ms";
    }

    /**
     * 异步任务-获取执行结果
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     */
    @GetMapping("async-wait-result")
    public String asyncWaitResult() throws InterruptedException, ExecutionException {
        Future<String> future = asyncTask.doAsyncTask();
        while (true) {
            if(future.isDone()){
                log.info("async task complete, result = {}", future.get());
                return "异步执行结果:" + future.get();
            }
        }
    }
}

启动项目:

  • 访问同步任务:http://localhost:8080/task
    接口返回结果:任务执行耗时:3008ms
    控制台日志
    2020-11-12 09:27:53.511 INFO 314716 — [nio-8080-exec-1] com.yanyuan.first.task.AsyncTask : thread name = http-nio-8080-exec-1, message = task start
    2020-11-12 09:27:56.513 INFO 314716 — [nio-8080-exec-1] com.yanyuan.first.task.AsyncTask : thread name = http-nio-8080-exec-1, message = task end

  • 访问异步任务:http://localhost:8080/async-task
    接口返回结果:任务执行耗时:5ms
    控制台日志
    2020-11-12 09:30:34.278 INFO 314716 — [ executor-1] com.yanyuan.first.task.AsyncTask : thread name = executor-1, message = async start
    2020-11-12 09:30:37.294 INFO 314716 — [ executor-1] com.yanyuan.first.task.AsyncTask : thread name = executor-1, message = async end

  • 访问异步任务并等待异步结果:http://localhost:8080/async-wait-result
    接口返回结果:异步执行结果:async execute complete
    控制台日志
    2020-11-12 09:32:28.546 INFO 314716 — [ executor-2] com.yanyuan.first.task.AsyncTask : thread name = executor-2, message = async start
    2020-11-12 09:32:31.547 INFO 314716 — [ executor-2] com.yanyuan.first.task.AsyncTask : thread name = executor-2, message = async end
    2020-11-12 09:32:31.547 INFO 314716 — [nio-8080-exec-9] c.y.first.controller.TaskController : async task complete, result = async execute complete

参考资料

项目地址
分支:async-task

本文地址:https://blog.csdn.net/yanyuan_1118/article/details/109200434