在现代的Web应用开发中,处理请求时需要考虑到系统的性能和响应速度。特别是在处理大量请求或者需要进行耗时操作时,采用异步多线程处理是一种常见的解决方案。Spring Boot提供了@Async注解来支持异步方法调用,结合合适的线程池配置,可以很容易地实现异步多线程处理,提升系统的并发能力和性能。
今日内容介绍,大约花费9分钟
图片
@Configuration@EnableAsyncpublic class AsyncConfiguration { @Bean("doSomethingExecutor") public Executor doSomethingExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 核心线程数:线程池创建时候初始化的线程数 executor.setCorePoolSize(10); // 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程 executor.setMaxPoolSize(20); // 缓冲队列:用来缓冲执行任务的队列大小 executor.setQueueCapacity(500); // 允许线程的空闲时间60秒:当超过了核心线程之外的线程在空闲时间到达之后会被销毁 executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix("do-something-"); // 缓冲队列满了之后的拒绝策略:由调用线程处理(一般是主线程 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); executor.initialize(); return executor; }}
在这个配置中,我们使用了ThreadPoolTaskExecutor作为线程池的实现,并且设置了一些关键参数,如核心线程数、最大线程数、缓冲队列大小等。如果不太了解线程池的小伙伴可以看一下之前介绍线程池介绍线程池的核心参数,线程池的执行原理知道
在需要异步执行的方法上使用@Async注解。这样的方法将会在一个单独的线程中执行,而不会阻塞主线程。
@Slf4j@Servicepublic class AsyncService { // 指定使用beanname为doSomethingExecutor的线程池 @Async("doSomethingExecutor") public CompletableFuture<String> doSomething(String message) throws InterruptedException { log.info("doSomethingExecutor thread name ={}", Thread.currentThread().getName()); Thread.sleep(1000); return CompletableFuture.completedFuture(message); }}
doSomething()方法被标记为异步方法,并且指定了使用名为"doSomethingExecutor"的线程池进行执行。
在某些情况下,我们可能需要等待多个异步任务执行完毕后再进行下一步操作,这时可以使用CompletableFuture来实现异步多结果的聚合。
@RestController@RequestMappingpublic class AsyncController { @Autowired private AsyncService asyncService; @GetMapping("/open/somethings") public List<String> somethings() throws InterruptedException { int count = 6; List<CompletableFuture<String>> futures = new ArrayList<>(); List<String> results = new ArrayList<>(); // 启动多个异步任务,并将 CompletableFuture 对象存储在列表中 for (int i = 1; i < count; i++) { CompletableFuture<String> future = asyncService.doSomething("index: "+i); futures.add(future); } for (CompletableFuture<String> future : futures) { String result = future.get(); // 阻塞等待异步任务完成并获取结果 results.add(result); } return results; }}
我们通过循环启动了多个异步任务,将返回的 CompletableFuture 对象存储在列表中。然后,我们再次循环遍历这些 CompletableFuture 对象,并调用 get() 方法来阻塞等待异步任务完成,获取结果。最后,将结果添加到结果列表中并返回
使用浏览器发送http://localhost:8888/open/somethings,结果如下
图片
发现使用多个线程执行方法
图片
@Async注解会在以下几个场景失效,使用了@Async注解,但就没有走多线程:
异步方法使用注解@Async的返回值只能为void或者Future及其子类,当返回结果为其他类型时,方法还是会异步执行,但是返回值都是null
本文链接:http://www.28at.com/showinfo-26-80194-0.htmlSpringBoot中的异步多线程使用及避坑指南
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
下一篇: AI时代的技术栈,你了解几分?