• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

解决SpringBoot中使用@Async注解失效的问题

springboot 搞代码 4年前 (2022-01-05) 17次浏览 已收录 0个评论

这篇文章主要介绍了解决SpringBoot中使用@Async注解失效的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

错误示例,同一个类中使用异步方法:

 package com.xqnode.learning.controller; import com.fasterxml.jackson.core.JsonProcessingException; import org.springframework.scheduling.annotation.Async; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; @RestController @RequestMapping("/test") public class TestController { @GetMapping("/async") public Map test() throws InterruptedException, JsonProcessingException { System.out.println("接收到请求。。。"); task(); Map map = new HashMap(); System.out.println("请求结束。。。"); map.put("msg", "操作成功"); map.put("code", "0"); return map; } @Async void task() throws InterruptedException { TimeUnit.SECONDS.sleep(5); System.out.println("线程任务执行结束。。。"); } } 

来分析下错误的原因:

当我使用postman调用该接口的时候发现,我预想中的立即返回并没有发生。后来查询资料发现,在controller调用本类中的异步方法,不会生效

正确示例:

 package com.xqnode.learning.controller; import com.xqnode.learning.service.AsyncService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/test") public cl<a style="color:transparent">来源gao*daima.com搞@代#码网</a>ass TestController { private static final Logger LOG = LoggerFactory.getLogger(TestController.class); @Autowired private AsyncService asyncService; @GetMapping("/async") public Map test() throws InterruptedException { LOG.info("接收到请求。。。"); asyncService.task(); Map map = new HashMap(); LOG.info("请求结束。。。"); map.put("msg", "操作成功"); map.put("code", "0"); return map; } } 

将异步调用放到service中:

 package com.xqnode.learning.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; @Service public class AsyncService { private static final Logger LOG = LoggerFactory.getLogger(AsyncService.class); @Async("asyncExecutor") public void task() throws InterruptedException { TimeUnit.SECONDS.sleep(5); LOG.info("线程任务执行结束。。。"); } } 

这时候再重启项目请求该接口,就会发现接口可以立即返回值。而task任务是异步执行的,5秒之后才会打印结果:

补充知识:springboot + @Async 实现异步方法之踩坑填坑

在使用@Async注解实现异步方法的时候,我们项目中实现了AsyncConfigurer接口来自定义线程池和异常处理。其中自定义线程池的代码如上图,异常处理项目中是自定义异常类实现AsyncUncaughtExceptionHandler 接口,这里未贴出代码。那么到底踩了什么坑呢?

第一:

加了@Async注解的方法调不起来。由于我不是项目及代码的原创,花了很多时间才分析出问题。经过仔细分析,由于业务场景需要,我们在项目启动的时候就创建了3个线程(也就是创建了3个任务)这正好占满了核心线程数(3个),当调到@Async的方法时,相当于有新的任务进来,结合线程池的原理可知,新的任务都会放到阻塞队列里面去,直到阻塞队列满了才可能会创建新的线程来执行任务或者执行饱和策略(这与Runtime.getRuntime().availableProcessors()能获取到的线程数有关),所以造成了异步方法调不起来的假象。

解决方法:根据实际情况将线程池的核心线程数和最大线程数调整到合适的值。

第二:

在解决了上一个问题后,又发现了新的问题,后面某段代码看不到执行的日志,也不知道错在哪里,没有错误日志。由于之前项目的日志并不详细,在逐步完善各处日志后,终于发现问题,报出了某个实体类没有默认构造函数的错误。在@Async异步方法中有一个把json转成实体bean的操作,由于这个bean创建了有参构造函数,却没有默认的无参构造函数,所以抛异常了,正好被getAsyncUncaughtExceptionHandler()捕捉到,由于当时此方法没有日志,也是花了点时间的。

解决方法:完善日志,给实体类加上无参构造函数。

通过这两个问题,自己也总结了一下,在使用线程池相关的知识时,一定要先了解原理,不然可能给自己挖坑,还有就是平常写代码时要养成写注释和打日志的习惯,否则出问题时可能要多花很久的时间找问题。

以上这篇解决SpringBoot中使用@Async注解失效的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持gaodaima搞代码网

以上就是解决SpringBoot中使用@Async注解失效的问题的详细内容,更多请关注gaodaima搞代码网其它相关文章!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:解决SpringBoot中使用@Async注解失效的问题

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址