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

 更新时间:2020年09月29日 09:51:22   作者:xqnode  
这篇文章主要介绍了解决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<Object, Object> test() throws InterruptedException, JsonProcessingException {
  System.out.println("接收到请求。。。");
  task();
  Map<Object, Object> 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 class TestController {

 private static final Logger LOG = LoggerFactory.getLogger(TestController.class);

 @Autowired
 private AsyncService asyncService;

 @GetMapping("/async")
 public Map<Object, Object> test() throws InterruptedException {
  LOG.info("接收到请求。。。");
  asyncService.task();
  Map<Object, Object> 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注解失效的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java 代码中预防空指针异常的处理办法

    java 代码中预防空指针异常的处理办法

    个人在做项目时,对NullPointerException的几点总结,请网友拍砖!!!多多提意见,
    2013-03-03
  • Java中JFrame实现无边框无标题方法

    Java中JFrame实现无边框无标题方法

    这篇文章主要介绍了Java中JFrame实现无边框无标题方法,本文直接给出代码实例,需要的朋友可以参考下
    2015-05-05
  • java实现租车系统

    java实现租车系统

    这篇文章主要为大家详细介绍了java实现租车系统,以及遇到的两个问题解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • 使用Java实现简单串口通信

    使用Java实现简单串口通信

    这篇文章主要介绍了使用Java实现简单串口通信,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • Spring中的EventListenerMethodProcessor组件详解

    Spring中的EventListenerMethodProcessor组件详解

    这篇文章主要介绍了Spring中的EventListenerMethodProcessor组件详解,EventListenerMethodProcessor 是 Spring 事件机制中非常重要的一个组件,它管理了一组EventListenerFactory组件,用来将应用中每个使用@EventListener注解定义的事件监听,需要的朋友可以参考下
    2023-12-12
  • Java List排序4种写法整理

    Java List排序4种写法整理

    这篇文章主要给大家介绍了关于Java List排序4种写法整理的相关资料,在有的时候我们会需要对List进行排序,在Java中如何实现呢,本文记录一下Java中对List的几种排序方式,需要的朋友可以参考下
    2023-08-08
  • JAVA读取二进制文件以及画图教程

    JAVA读取二进制文件以及画图教程

    由于项目需要,需要对二进制文件进行读取,所以这篇文章主要给大家介绍了关于JAVA读取二进制文件以及画图的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • 带你了解10道java入门面试题

    带你了解10道java入门面试题

    面试题相信大家都不陌生,想要一个好的工作面试题必不可少的,下面和小编一起来学习与了解Java当中有有些什么面试题吧,希望能给你带来帮助
    2021-08-08
  • JAVA 流程控制专项精讲

    JAVA 流程控制专项精讲

    不喜欢罗里吧嗦,讲的很精简易懂。从基础开始讲,后续会讲到JAVA高级,中间会穿插面试题和项目实战,希望能给大家带来帮助
    2022-03-03
  • Java双重校验锁单例原理

    Java双重校验锁单例原理

    大家好,本篇文章主要讲的是Java双重校验锁单例原理,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01

最新评论