写在最前
异步处理不用阻塞当前线程来等待执行完成,而是允许后续操作,直至其它线程将其执行完成,并回调通知此线程。有些业务逻辑可以不用同步处理,并且执行时间长,多数情况都会使用异步处理,直接返回,提升吞吐量。例如:
- 发送短信、邮件;
- 卡券或优惠券发放;
- App消息推送;
- 工作流性质的异步任务;
Spring Boot 整合异步任务
Demo 地址:mingyue-springboot-async
1.开启异步任务
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync // 开启异步任务
@SpringBootApplication
public class MingYueSpringbootAsyncApplication {
public static void main(String[] args) {
SpringApplication.run(MingYueSpringbootAsyncApplication.class, args);
}
}
2.编写异步任务
import com.csp.mingyue.async.model.MingYueUser;
import java.util.concurrent.Future;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
/** @author Strive */
@Slf4j
@Component
public class MingYueUserAsyncTask {
/** 查询用户部门信息 */
@Async
@SneakyThrows
public Future<Boolean> queryDeptInfo(MingYueUser mingYueUser) {
long start = System.currentTimeMillis();
Thread.sleep(1000);
long end = System.currentTimeMillis();
log.info("{}:查询用户部门信息耗时:({})毫秒", mingYueUser.getUsername(), (end - start));
return new AsyncResult<>(true);
}
/** 查询用户角色信息 */
@Async
@SneakyThrows
public Future<Boolean> queryRoleInfo(MingYueUser mingYueUser) {
long start = System.currentTimeMillis();
Thread.sleep(500);
long end = System.currentTimeMillis();
log.info("{}:查询用户角色信息耗时:({})毫秒", mingYueUser.getUsername(), (end - start));
return new AsyncResult<>(true);
}
}
3.接口测试
import com.csp.mingyue.async.model.MingYueUser;
import com.csp.mingyue.async.service.MingYueUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** @author Strive */
@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
public class MingYueUserController {
private final MingYueUserService mingYueUserService;
@GetMapping("/{userId}")
public ResponseEntity<MingYueUser> queryUserById(@PathVariable Long userId) {
return ResponseEntity.ok(mingYueUserService.queryUserById(userId));
}
}
开启异步任务,执行日志如下:
21:37:49.892 INFO 17668 --- [ task-2] c.c.m.async.tasks.MingYueUserAsyncTask : mingyue:查询用户角色信息耗时:(511)毫秒
21:37:50.393 INFO 17668 --- [ task-1] c.c.m.async.tasks.MingYueUserAsyncTask : mingyue:查询用户部门信息耗时:(1012)毫秒
21:37:50.394 INFO 17668 --- [nio-8080-exec-1] c.c.m.async.service.MingYueUserService : 任务全部完成,总耗时:(1026)毫秒
关闭异步任务,执行日志如下:
21:39:38.235 INFO 7032 --- [nio-8080-exec-1] c.c.m.async.tasks.MingYueUserAsyncTask : mingyue:查询用户部门信息耗时:(1001)毫秒
21:39:38.747 INFO 7032 --- [nio-8080-exec-1] c.c.m.async.tasks.MingYueUserAsyncTask : mingyue:查询用户角色信息耗时:(510)毫秒
21:39:38.747 INFO 7032 --- [nio-8080-exec-1] c.c.m.async.service.MingYueUserService : 任务全部完成,总耗时:(1513)毫秒
通过开关闭异步任务,对比结果,高下立判!
- 异步任务 总耗时:(1026)毫秒;
- 同步任务 总耗时:(1513)毫秒;
4.配置线程池
@Slf4j
@Configuration
public class MingYueUserInfoThreadPoolConfig {
@Bean(name = "userInfoThreadPoolExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
log.info("---------- 线程池开始加载 ----------");
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
// 核心线程池大小
threadPoolTaskExecutor.setCorePoolSize(15);
// 最大线程数
threadPoolTaskExecutor.setMaxPoolSize(30);
// 队列容量
threadPoolTaskExecutor.setQueueCapacity(15);
// 活跃时间
threadPoolTaskExecutor.setKeepAliveSeconds(60);
// 主线程等待子线程执行时间
threadPoolTaskExecutor.setAwaitTerminationSeconds(60);
// 线程名字前缀
threadPoolTaskExecutor.setThreadNamePrefix("user-info-");
// RejectedExecutionHandler:当pool已经达到max-size的时候,如何处理新任务
// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
threadPoolTaskExecutor.initialize();
log.info("---------- 线程池加载完成 ----------");
return threadPoolTaskExecutor;
}
}
执行日志如下:
# pool-executor-2 / pool-executor-1 使用了线程池
22:00:04.180 INFO 16788 --- [pool-executor-2] c.c.m.async.tasks.MingYueUserAsyncTask : mingyue:查询用户角色信息耗时:(512)毫秒
22:00:04.679 INFO 16788 --- [pool-executor-1] c.c.m.async.tasks.MingYueUserAsyncTask : mingyue:查询用户部门信息耗时:(1011)毫秒
22:00:04.679 INFO 16788 --- [nio-8080-exec-1] c.c.m.async.service.MingYueUserService : 任务全部完成,总耗时:(1020)毫秒
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/78343.html