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

作者:xqnode 时间:2023-08-24 07:38:46 

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


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注解失效的问题

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

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

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

第一:

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

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

第二:

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

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

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

来源:https://blog.csdn.net/xqnode/article/details/81538499

标签:SpringBoot,@Async,注解
0
投稿

猜你喜欢

  • C# 8.0中的范围类型(Range Type)示例详解

    2023-04-11 22:26:10
  • Java设计模式之java原型模式详解

    2022-04-01 03:16:40
  • C#启动进程的几种常用方法

    2023-06-18 04:13:48
  • Android 蓝牙开发实例解析

    2021-06-04 03:34:37
  • SpringBoot通过源码探究静态资源的映射规则实现

    2022-03-26 19:05:53
  • SSH框架网上商城项目第10战之搭建商品类基本模块

    2023-11-12 14:00:29
  • Java基本数据类型(动力节点java学院整理)

    2022-09-26 12:14:13
  • SpringCloud Eureka的使用教程

    2022-03-23 22:30:59
  • Java并发编程之JUC并发核心AQS同步队列原理剖析

    2023-01-15 15:14:37
  • SpringMVC使用MultipartResolver实现文件上传

    2023-02-19 08:34:38
  • 解决idea web 配置相对路径问题

    2022-01-12 06:48:40
  • 算法证明每一位都相同十进制数不是完全平方数

    2022-06-21 23:00:46
  • 深入解析java中的静态代理与动态代理

    2023-08-23 13:10:56
  • SpringBoot集成Spring security JWT实现接口权限认证

    2023-02-02 07:31:08
  • shiro之记住登录信息

    2023-03-06 18:39:13
  • C#多线程之线程通讯(AutoResetEvent)

    2021-12-26 01:48:55
  • Android RecyclerView实现悬浮吸顶、分隔线、到底提示效果

    2022-02-26 16:59:39
  • C# 游戏外挂实现核心代码

    2021-12-28 14:47:40
  • 在Android中通过Intent使用Bundle传递对象的使用方法

    2023-04-23 10:15:38
  • Java编写Mapreduce程序过程浅析

    2023-02-26 02:53:20
  • asp之家 软件编程 m.aspxhome.com