SpringBoot实现异步调用的方法

在Java中使用Spring Boot实现异步请求和异步调用是一个常见的需求,可以提高应用程序的性能和响应能力。以下是实现这两种异步操作的基本方法:

一、异步请求(Asynchronous Request)

异步请求允许客户端发送请求后立即返回,而不需要等待服务器处理完成,异步调用允许在服务端异步执行方法,不阻塞主线程。

二、在 Spring Boot 中,实现异步调用主要有以下几种方法:
1. 使用 @Async 注解
步骤:
  1. 启用异步支持 :在主类上添加 @EnableAsync
  2. 定义异步方法 :在需要异步执行的方法上使用 @Async 注解。
  3. 自定义线程池(可选):提高异步任务的线程管理效率,以便异步方法能够在独立的线程中执行
示例代码:

主类:

复制代码
package com.work;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication(scanBasePackages = {"com.work.*"})
@EnableAsync
//@EnableScheduling
public class SpringBootWorkApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringBootWorkApplication.class, args);
	}
}

异步方法:

复制代码
package com.work.service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
/**
 * 异步调用service
 * @author summer
 */
@Service
@Slf4j
public class AsyncService {
    /**
	 * 使用 @Async 注解 实现异步调用
	 * taskExecutor为自定义线程池,指定自定义线程池
	 * @return
	 * @throws InterruptedException
	 */
	@Async("taskExecutor")
    public void async(){
		log.info("async异步任务开始: " + Thread.currentThread().getName());
		try {
			// 模拟耗时操作(实际工作中,此处写业务逻辑处理)  
			Thread.sleep(30000); 
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
		log.info("async异步任务完成");
    }
}
自定义线程池(可选):
复制代码
package com.work.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
 * 自定义异步线程执行线程池
 * @author summer
 *
 */
@Configuration
public class ExecutorConfig {

    @Bean(name = "taskExecutor")
    public TaskExecutor  taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(50);
        executor.setThreadNamePrefix("TaskExecutor-");
        executor.initialize();
        return executor;
    }
}

@Async("taskExecutor") 中指定自定义线程池。

调用:
复制代码
package com.work.controller;
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 com.work.common.result.CommonResult;
import com.work.service.AsyncService;
import lombok.extern.slf4j.Slf4j;

/**
 * 测试异步执行Controller
 * @author summer
 *
 */
@RestController
@RequestMapping("/async")
@Slf4j
public class AsyncTestController {
	
	@Autowired
	private AsyncService asyncService;
	
	@GetMapping("/async")
	public CommonResult<String> async() {
		asyncService.async();
		log.info("async异步任务调用成功");
		return CommonResult.success("async异步任务调用成功");
	}
}

异步方法休眠30秒,可以看到控制台打印的日志

线程池配置建议
  • CPU 密集型任务 :建议核心线程数为 CPU 核心数的 n 倍,最大线程数为核心线程数的 2 倍。
  • IO 密集型任务:建议核心线程数设置为较大的值,最大线程数可以为核心线程数的 2 倍甚至更多。

合理配置线程池可以避免线程饥饿和死锁等问题,提升系统的吞吐量。

2. 使用 Java 原生线程池

Spring 提供线程池,但可以直接使用 Java 原生的线程池来实现异步。

示例代码:
复制代码
package com.work.service;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;

/**
 * 异步调用service
 * @author summer
 *
 */
@Service
@Slf4j
public class AsyncService{
	
	/**
	 * 使用 Java 原生线程池来实现异步调用
	 */
	public void asyncThreadPool() {
		ThreadPoolExecutor pool=new ThreadPoolExecutor(5, 10, 
				2, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(100),new ThreadPoolExecutor.CallerRunsPolicy());
		pool.execute(() -> {
			log.info("asyncThreadPool异步任务开始: " + Thread.currentThread().getName());
            try {
            	// 模拟耗时操作(实际工作中,此处写业务逻辑处理)  
                Thread.sleep(30000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("asyncThreadPool异步任务完成");
        });
    }
}
调用:
复制代码
package com.work.controller;
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 com.work.common.result.CommonResult;
import com.work.service.AsyncService;
import lombok.extern.slf4j.Slf4j;

/**
 * 测试异步执行Controller
 * @author summer
 *
 */
@RestController
@RequestMapping("/async")
@Slf4j
public class AsyncTestController {
	@Autowired
	private AsyncService asyncService;
	
	@GetMapping("/asyncThreadPool")
	public CommonResult<String> asyncThreadPool() {
		asyncService.asyncThreadPool();
		log.info("asyncThreadPool异步任务调用成功");
		return CommonResult.success("asyncThreadPool异步任务调用成功");
	}
}

异步方法休眠30秒,可以看到控制台打印的日志

3. 使用 Spring 的 TaskExecutor

TaskExecutor 是 Spring 提供的抽象接口,适合用来执行异步任务。

配置 TaskExecutor:
复制代码
package com.work.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
 * 自定义异步线程执行线程池
 * @author summer
 *
 */
@Configuration
public class ExecutorConfig {

    @Bean(name = "taskExecutor")
    public TaskExecutor  taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(50);
        executor.setThreadNamePrefix("TaskExecutor-");
        executor.initialize();
        return executor;
    }
}
示例代码:
复制代码
package com.work.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
/**
 * 异步调用service
 * @author summer
 *
 */
@Service
@Slf4j
public class AsyncService{
	@Autowired
	private TaskExecutor taskExecutor;
	
	/**
	 * 使用 Spring 的 TaskExecutor 来实现异步调用
	 */
	public void asyncExecutor() {
        taskExecutor.execute(() -> {
        	log.info("asyncExecutor异步任务开始:" + Thread.currentThread().getName());
            try {
            	// 模拟耗时操作(实际工作中,此处写业务逻辑处理)  
                Thread.sleep(30000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("asyncExecutor异步任务完成");
        });
    }
}
调用:
复制代码
package com.work.controller;
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 com.work.common.result.CommonResult;
import com.work.service.AsyncService;
import lombok.extern.slf4j.Slf4j;

/**
 * 测试异步执行Controller
 * @author summer
 *
 */
@RestController
@RequestMapping("/async")
@Slf4j
public class AsyncTestController {
	@Autowired
	private AsyncService asyncService;
	
	@GetMapping("/asyncExecutor")
	public CommonResult<String> asyncExecutor() {
		asyncService.asyncExecutor();
		log.info("asyncExecutor异步任务调用成功");
		return CommonResult.success("asyncExecutor异步任务调用成功");
	}
}

异步方法休眠30秒,可以看到控制台打印的日志

三、什么时候使用异步请求

异步请求在以下情况下特别有用:

  • 长时间运行的任务:例如文件上传、复杂计算、大量数据处理等。
  • I/O操作:例如数据库查询、调用外部API、文件读写等。
  • 资源密集型任务:例如图像处理、视频编码等。
四、总结

方法

优点

缺点

@Async 注解

简单易用,与 Spring 集成良好

需要 Spring 容器管理的 Bean 才能生效

ExecutorService

更底层、更灵活

手动管理线程池

TaskExecutor

Spring 提供的抽象,方便扩展

配置稍显复杂

这些示例展示了如何在Spring Boot中实现异步请求和异步调用。Spring Boot提供了`@Async`注解和`Java原生线程池`、`TaskExecutor`来实现这一功能,提高了应用程序的并发处理能力,开发者可以根据不同的需求选择合适的异步处理方式。

合理配置线程池,以确保最佳性能和资源利用,正确处理异步任务中的异常,以及在合适的场景中应用异步处理技术,是开发高性能应用的关键。

相关推荐
咩咩啃树皮3 小时前
第40篇:Vue3组件化开发精讲——组件拆分、复用、父子通信、工程化架构
java·前端·架构
鱟鲥鳚3 小时前
Spring Boot 集成 LangChain4j:从模型调用到 Tool Calling(Demo版)
java·spring boot
大模型码小白4 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
腾渊信息科技公司5 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
爱笑的源码基地6 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
wuqingshun3141596 小时前
TCP超时重传机制是为了解决什么问题?
java
莫逸风9 小时前
【AgentScope 2.0】 0. 学习指南
java·llm·agent·agentscope
隔窗听雨眠9 小时前
Spring Boot在云原生时代的编程范式革新研究
spring boot·后端·云原生
z123456789869 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
yaoxin52112310 小时前
470. Java 反射 - Member 接口与 AccessFlag
java·开发语言·python