20.异步方法
构建
IDEA新建项目 选择 Web
或者POM引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
编码
创建实体类
@JsonIgnoreProperties(ignoreUnknown=true)
public class User {
private String name;
private String blog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBlog() {
return blog;
}
public void setBlog(String blog) {
this.blog = blog;
}
@Override
public String toString() {
return "User [name=" + name + ", blog=" + blog + "]";
}
}
创建请求的service
@Service
public class GitHubLookupService {
private static final Logger logger = LoggerFactory.getLogger(GitHubLookupService.class);
private final RestTemplate restTemplate;
public GitHubLookupService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
@Async
public CompletableFuture<User> findUser(String user) throws InterruptedException {
logger.info("Looking up " + user);
String url = String.format("https://api.github.com/users/%s", user);
User results = restTemplate.getForObject(url, User.class);
// Artificial delay of 1s for demonstration purposes
Thread.sleep(10000L);
return CompletableFuture.completedFuture(results);
}
}
通过,RestTemplate去请求,另外加上类@Async 表明是一个异步任务。
开启异步任务:
@SpringBootApplication
@EnableAsync
public class SpringbootAsyncApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootAsyncApplication.class, args);
}
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("GithubLookup-");
executor.initialize();
return executor;
}
}
@EnableAsync 注释 开启Spring 运行 @Async的后台线程池
将并发线程限制为两个,队列大小限制为500个
测试
创建测试类
@Component
public class AppRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(AppRunner.class);
private final GitHubLookupService gitHubLookupService;
public AppRunner(GitHubLookupService gitHubLookupService) {
this.gitHubLookupService = gitHubLookupService;
}
@Override
public void run(String... args) throws Exception {
// Start the clock
long start = System.currentTimeMillis();
// Kick of multiple, asynchronous lookups
CompletableFuture<User> page1 = gitHubLookupService.findUser("PivotalSoftware");
CompletableFuture<User> page2 = gitHubLookupService.findUser("CloudFoundry");
CompletableFuture<User> page3 = gitHubLookupService.findUser("Spring-Projects");
// Wait until they are all done
CompletableFuture.allOf(page1,page2,page3).join();
// Print results, including elapsed time
logger.info("Elapsed time: " + (System.currentTimeMillis() - start));
logger.info("--> " + page1.get());
logger.info("--> " + page2.get());
logger.info("--> " + page3.get());
}
}
启动程序,控制台打印如下
2020-03-15 20:43:26.744 INFO 1656 --- [ GithubLookup-2] c.x.s.service.GitHubLookupService : Looking up CloudFoundry
2020-03-15 20:43:26.744 INFO 1656 --- [ GithubLookup-1] c.x.s.service.GitHubLookupService : Looking up PivotalSoftware
2020-03-15 20:43:38.077 INFO 1656 --- [ GithubLookup-1] c.x.s.service.GitHubLookupService : Looking up Spring-Projects
2020-03-15 20:43:49.247 INFO 1656 --- [ main] com.xiaofine.springbootasync.AppRunner : Elapsed time: 22515
2020-03-15 20:43:49.247 INFO 1656 --- [ main] com.xiaofine.springbootasync.AppRunner : --> User [name=Pivotal Software, Inc., blog=http://pivotal.io]
2020-03-15 20:43:49.247 INFO 1656 --- [ main] com.xiaofine.springbootasync.AppRunner : --> User [name=Cloud Foundry, blog=https://www.cloudfoundry.org/]
2020-03-15 20:43:49.247 INFO 1656 --- [ main] com.xiaofine.springbootasync.AppRunner : --> User [name=Spring, blog=https://spring.io/projects]
2020-03-15 20:43:49.249 INFO 1656 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'taskExecutor'
可以卡的前面2个方法分别在GithubLookup-1 和GithubLookup-2执行,第三个在GithubLookup-2执行,注意因为在配置线程池的时候最大线程为2.如果你把线程池的个数为3的时候,耗时减少。
如果去掉@Async,你会发现,执行这三个方法都在main线程中执行。耗时总结,如下:
2020-03-15 20:47:17.499 INFO 8256 --- [ main] c.x.s.service.GitHubLookupService : Looking up PivotalSoftware
2020-03-15 20:47:29.058 INFO 8256 --- [ main] c.x.s.service.GitHubLookupService : Looking up CloudFoundry
2020-03-15 20:47:40.204 INFO 8256 --- [ main] c.x.s.service.GitHubLookupService : Looking up Spring-Projects
2020-03-15 20:47:51.380 INFO 8256 --- [ main] com.xiaofine.springbootasync.AppRunner : Elapsed time: 33881
2020-03-15 20:47:51.380 INFO 8256 --- [ main] com.xiaofine.springbootasync.AppRunner : --> User [name=Pivotal Software, Inc., blog=http://pivotal.io]
2020-03-15 20:47:51.380 INFO 8256 --- [ main] com.xiaofine.springbootasync.AppRunner : --> User [name=Cloud Foundry, blog=https://www.cloudfoundry.org/]
2020-03-15 20:47:51.380 INFO 8256 --- [ main] com.xiaofine.springbootasync.AppRunner : --> User [name=Spring, blog=https://spring.io/projects]
2020-03-15 20:47:51.382 INFO 8256 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'taskExecutor'
官网地址
https://spring.io/guides/gs/async-method/
问题1:
原本官方示例是如下,会报错Connect Reset 可能是提供的api限制
Thread.sleep(1000L);
调大十倍就没问题了
Thread.sleep(10000L);
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论。
文章标题:20.异步方法
本文作者:xiaofine
发布时间:2020-03-21, 21:47:58
最后更新:2020-03-22, 08:22:32
原始链接:https://xiaofine1122.github.io/2020/03/21/20.%E5%BC%82%E6%AD%A5%E6%96%B9%E6%B3%95/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。