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
上一篇: AMD x86份额创有史以来最高记录 分析师:这还不够
下一篇: 这样的老婆谁能养得起
推荐阅读
-
Spring Boot利用@Async异步调用:使用Future及定义超时详解
-
Spring Boot利用@Async如何实现异步调用:自定义线程池
-
Spring Boot利用@Async异步调用:ThreadPoolTaskScheduler线程池的优雅关闭详解
-
Spring Boot 使用WebAsyncTask异步返回结果
-
Spring Boot异步输出Logback日志方法详解
-
详解Spring Boot 异步执行方法
-
Spring Boot @Scheduled定时任务代码实例解析
-
spring boot使用自定义的线程池执行Async任务
-
深入理解spring boot异步调用方式@Async
-
Spring Boot 使用WebAsyncTask异步返回结果