异步注解@Async使用记录

使用场景:需要执行某个方法但不需等待该方法的执行结果或者需要执行多个方法但这些方法不需要先后执行,可以通过声明并调用异步方法实现.因为每执行一个异步方法都需要从线程池中申请并占用一个线程,为避免线程资源过度损耗,需要自行维护线程池。

 

1 启动类上加 @EnableAsync 表示开启异步注解

2 controller:调用异步方法:调用无返回值的异步方法时,无需等待其执行结束;对于有返回值的异步方法时,获取其返回值时,需要同步等待

复制代码
package kun.async;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;


@RestController
public class AsyncController {
    @Autowired
    private AsyncService asyncService;

    @GetMapping("/async-task")
    public void doAsyncTask() {
        System.out.println("doAsyncTask begin");
        asyncService.asyncInVoid();
        System.out.println("doAsyncTask end");
    }

    @GetMapping("/async-task-with-result")
    public Integer doAsyncTaskWithResult() {
        System.out.println("doAsyncTaskWithResult begin");
        Future<Integer> result = asyncService.asyncWithResult();
        try{
            System.out.println("doAsyncTaskWithResult end");
            return result.get();
        } catch (ExecutionException | InterruptedException ex) {
            throw new RuntimeException("execute failed");
        }
    }

    @GetMapping("/async-task-with-result-2")
    public Integer doAsyncTaskWithResult2() {
        System.out.println("doAsyncTaskWithResult2 begin");
        Future<Integer> result = asyncService.asyncWithResult();
        try{
            System.out.println("doAsyncTaskWithResult end");
            Thread.sleep(15000);
            // get()方法会一直阻塞,方法最后的执行时间,依赖执行时间最长的线程
            return result.get();
        } catch (ExecutionException | InterruptedException ex) {
            throw new RuntimeException("execute failed");
        }
    }
}
复制代码

3 service,声明异步方法

复制代码
package kun.async;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;

@Service
@Slf4j
public class AsyncService {
    /**
     * 异步调用示例,无返回值
     */
    @Async
    public void asyncInVoid() {
        System.out.println("asyncInVoid begin");
        try {
            Thread.sleep(5000);
            System.out.println("current time is: " + System.currentTimeMillis());
        } catch (InterruptedException ex) {
            log.error("thread sleep failed: ", ex);
        }
        System.out.println("asyncInVoid end");
    }

    /**
     * 异步调用示例,有返回值
     *
     * @return
     */
    @Async
    public Future<Integer> asyncWithResult() {
        System.out.println("asyncWithResult begin");
        try {
            Thread.sleep(10000);
            System.out.println("current time is: " + System.currentTimeMillis());
        } catch (InterruptedException ex) {
            log.error("thread sleep failed: ", ex);
        }
        System.out.println("asyncWithResult end");
        return new AsyncResult<Integer>(1000);
    }
}
复制代码

4 自定义异步方法调用线程池

异步方法运行在独立的线程中,不会阻塞主线程的执行。异步方法执行所需的线程默认是从SpringBoot提供线程池中申请线程。为控制线程的使用和回收,商用环境一般使用自定义线程池,以保证异步方法的调用可控。SpringBoot提供AsyncTaskExecutor用于实现自定义异步方法调用线程池。示例代码如下:

复制代码
@Configuration
public class AsyncConfig {
    private static final int MAX_POOL_SIZE = 50;
    private static final int CORE_POOL_SIZE = 20;
    private static final int WAIT_QUEUE_CAPACITY = 1000;

    @Bean("taskExecutor")
    public AsyncTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setThreadNamePrefix("async-task-thread-pool-");
        taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
        taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        taskExecutor.setQueueCapacity(WAIT_QUEUE_CAPACITY);
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        taskExecutor.initialize();
        return taskExecutor;
    }
}
复制代码

 

posted @   杨吃羊  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示