Spring Boot中加@Async和不加@Async有什么区别?设置核心线程数、设置最大线程数、设置队列容量是什么意思?直接在yml中配置线程池

在 Spring 中,@Async 注解用于将方法标记为异步执行的方法。当使用 @Async 注解时,该方法将在单独的线程中执行,而不会阻塞当前线程。这使得方法可以在后台执行,而不会影响主线程的执行。

在您提供的代码示例中,a1() 和 a2() 方法都被标记为 @Async,意味着它们将以异步方式执行。这意味着当调用这些方法时,它们将会在单独的线程中执行,而不会等待方法执行完成。

如果不使用 @Async 注解,则方法将会以同步方式执行。也就是说,当调用这些方法时,程序将会阻塞在方法执行处,直到方法执行完成才会继续执行后续代码。

因此,加上 @Async 注解的方法能够实现并发执行,而不加 @Async 注解的方法则会按照顺序逐个执行。根据您的代码示例,加上 @Async 注解后,a1() 和 a2() 方法将会同时启动并发执行,而不会相互阻塞。

需要注意的是,使用 @Async 注解需要配置一个任务执行器(Task Executor)来处理异步方法的调用。如果在 Spring Boot 项目中使用 @EnableAsync 注解来启用异步支持,Spring 将会自动配置默认的任务执行器。如果未配置任务执行器,则异步方法将在调用线程中执行,而不会启动新的线程来执行。

手动配置任务执行器

配置任务执行器(Task Executor)

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableAsync
public class AsyncConfig {
	// 配置任务执行器
	@Bean(name = "taskExecutor")
	public Executor taskExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

		// 设置核心线程数
		executor.setCorePoolSize(10);

		// 设置最大线程数
		executor.setMaxPoolSize(20);

		// 设置队列容量
		executor.setQueueCapacity(100);

		// 设置线程活跃时间(秒)
		executor.setKeepAliveSeconds(60);

		// 设置线程名称前缀
		executor.setThreadNamePrefix("Async-");

		// 设置拒绝策略
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

		// 初始化线程池
		executor.initialize();

		return executor;
	}
}

设置核心线程数、设置最大线程数和设置队列容量是线程池中的一些重要参数。

  • 核心线程数(Core Thread Pool Size):指的是线程池中保持的线程数量。即使这些线程处于空闲状态,它们也会一直存在于线程池中,以备接收新的任务。当线程池中的线程数量小于核心线程数时,新的任务将会创建新的线程来执行。
  • 最大线程数(Maximum Pool Size):指的是线程池中允许的最大线程数量。当线程池中的线程数量达到核心线程数时,如果还有新的任务需要执行,线程池将会再创建新的线程,直到达到最大线程数为止。当线程池中的线程数量达到最大值且队列也已满时,则会拒绝执行新的任务。
  • 队列容量(Queue Capacity):指的是线程池中任务队列可以容纳的最大任务数量。当线程池中的线程数量达到核心线程数时,如果还有新的任务需要执行,线程池将会将这些任务添加到任务队列中。如果任务队列已满,则会根据线程池的策略来处理这些被拒绝的任务。

这些参数的设置应该根据应用程序的需求和系统的资源来确定。过小的核心线程数和队列容量可能导致任务长时间排队等待执行,而过大的最大线程数则可能会消耗过多的系统资源。

定时任务A1

java 复制代码
@Component
@EnableScheduling
public class A1 {
	@Async("taskExecutor")
	@Scheduled(cron = "0 0/1 * * * ?")
	public void a1(){
		for (int i = 0; i < 1000; i++) {
			System.out.println("我是a1");
		}
	}
}

定时任务A2

java 复制代码
@Component
@EnableScheduling
public class A2 {
	@Async("taskExecutor")
	@Scheduled(cron = "0 0/1 * * * ?")
	public void a2(){
		for (int i = 0; i < 1000; i++) {
			System.out.println("我是a2");
		}
	}
}

加了@Async输出结果大概如下

A1和A2多线程交替执行,并发

bash 复制代码
我是a1
我是a2
我是a1
我是a2
我是a1
我是a2
我是a1
我是a2
我是a1
我是a2
...

不加@Async输出结果大概如下

先执行完A1才会去执行A2,按顺序执行,阻塞

bash 复制代码
我是a1
我是a1
我是a1
我是a1
我是a1
我是a2
我是a2
我是a2
我是a2
我是a2
...

当涉及到设置线程池的核心线程数、最大线程数和队列容量时,需要根据具体的应用场景和需求来确定。下面是一些示例:

场景一:Web 服务器请求处理

假设有一个 Web 服务器,需要处理大量的并发请求。在这种情况下,可以考虑以下设置:

  • 核心线程数:根据服务器的负载和处理能力,设置一个适当的核心线程数,例如设置为 CPU 核心数的两倍。
  • 最大线程数:根据服务器的资源和性能,设置一个合理的最大线程数,例如设置为 CPU 核心数的四倍。
  • 队列容量:如果服务器的处理能力超过了核心线程数和最大线程数,可以设置一个适当的队列容量,以便将超出处理能力的请求暂存到队列中,例如使用一个有界队列。

场景二:后台任务处理

假设有一个后台任务需要处理大量的耗时操作,比如文件处理、数据导入等。在这种情况下,可以考虑以下设置:

  • 核心线程数:根据系统的负载和任务的数量,设置一个适当的核心线程数,例如设置为固定值,如10个线程。
  • 最大线程数:根据系统的资源和性能,设置一个合理的最大线程数,例如设置为20个线程。
  • 队列容量:如果任务数量超过了核心线程数和最大线程数,可以设置一个适当的队列容量,以便将超出处理能力的任务暂存到队列中,例如使用一个无界队列。

需要根据具体的应用场景和系统要求来灵活调整这些参数。合理设置这些参数可以提高系统的性能和资源利用率,避免因为线程过多或过少导致的性能问题或资源浪费。

yml中配置线程池

也可以直接在.yml中配置线程池大小

yaml 复制代码
spring:
  task:
    scheduling:
      # 线程池大小
      pool:
        size: 30
      # 线程名前缀
      thread-name-prefix: myTask-

定时任务A1

java 复制代码
@Component
@EnableScheduling
@EnableAsync
public class A1 {
	@Async
	@Scheduled(cron = "0 0/1 * * * ?")
	public void a1(){
		for (int i = 0; i < 1000; i++) {
			System.out.println("我是a1");
		}
	}
}

定时任务A2

java 复制代码
@Component
@EnableScheduling
@EnableAsync
public class A2 {
	@Async
	@Scheduled(cron = "0 0/1 * * * ?")
	public void a2(){
		for (int i = 0; i < 1000; i++) {
			System.out.println("我是a2");
		}
	}
}
相关推荐
laufing3 分钟前
java web 基础 ---- servlet
java·servlet·web开发
程序猿乐锅7 分钟前
【苍穹外卖|Day01】项目初识:从多模块结构到 OpenAPI 接口文档踩坑
java·spring·maven·mybatis
jasnet_u7 分钟前
SpringCloud中服务集成PlumeLog日志系统
spring·spring cloud·plumelog·日志收集
李白的天不白9 分钟前
针对你遇到的 Client.Timeout exceeded 问题,我判断是防火墙拦截了 HTTPS 流量
java
linweidong13 分钟前
Java 后端开发面试 50 个高频易混淆知识点详解
java·spring boot·spring·spring cloud·面试·mybatis·spring事务
码语智行13 分钟前
应用启动和关闭监听器功能分析
java·spring boot
Resky081814 分钟前
什么是 Spring IOC:倒过来让容器帮你 new,而不是你到处 new
java·spring
AutumnWind042014 分钟前
【JDK动态代理源码梳理】
java·后端·spring
AI进阶客栈14 分钟前
开源 MQ Master:Spring Boot 统一管控 5 大消息队列
spring boot·后端·开源