SpringBoot之异步调用(ThreadPoolTaskExecutor类)

文章介绍了如何在SpringBoot项目中配置和使用ThreadPoolTaskExecutor进行多线程处理,包括默认配置和自定义配置。同时,详细讲解了@Async注解的使用方法,以及异步调用的生效条件和失效场景,提供了一个测试示例来验证异步执行的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

平时大家在谈及异步调用及多线程时候总是能说上两句,但是实际动手又是另一回事,今天项目中涉及到了异步调用所以就记录一下

配置多线程

ThreadPoolTaskExecutor

SpringBoot默认情况下帮我们自动配置了ThreadPoolTaskExecutor到IOC容器中,我们需要的时候直接注入使用即可。

默认参数:
核心线程数:8
最大线程数:2147483647
线程等待超时时间:60
当前活跃的线程数:5
线程池内线程的名称:ThreadPoolTaskExecutor test task-4
前缀:task-

当然如果有需要也可以自己进行配置

配置ThreadPoolTaskExecutor参数

在启动类Application中,向容器中添加参数重新配置后的ThreadPoolTaskExecutor实例,需要借助两个注解:
@Configuration        //声明这是一个配置类
@Bean        //声明一个bean

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@Configuration
public class ThreadPoolConfiguration {

    @Bean
    public ThreadPoolTaskExecutor myThreadPool(){
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //设置核心线程数
        taskExecutor.setCorePoolSize(20);
        //设置最大线程数
        taskExecutor.setMaxPoolSize(100000);
        //设置线程空闲等待时间(单位:秒)
        taskExecutor.setKeepAliveSeconds(60);
        //设置任务等待队列的大小
        taskExecutor.setQueueCapacity(10);
        // 设置线程池内线程名称的前缀-------阿里编码规约推荐--方便出错后进行调试
        taskExecutor.setThreadNamePrefix("task-myThreadPool-");
        //设置任务的拒绝策略
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
//        taskExecutor.setWaitForTasksToCompleteOnShutdown(true); //默认false
        //初始化
        taskExecutor.initialize();
        return taskExecutor;
    }

}

SpringBoot中的异步调用

@Async注解

  • @Async注解可以配置在类或者方法上,若配置在类上则说明这个类下的所有方法都将支持异步调用
  • 异步方法所属的类应该是spring管理的类;

1:定义任务方法

创建包com.***.***.async,在该包下创建AsyncTask类,注意需要将该类放入容器中,然后在该类中定义一个方法,在方法上添加@Async注解表明需要异步执行,最后在配置类上开启异步任务

@Component
public class AsyncTask {

    @Async("myThreadPool")
    public void myAsync(){
        System.out.println("hello\n\n" + Thread.currentThread().getName());
    }

}

"myThreadPool" 是一个可选的参数,用于指定使用哪个具体的异步执行器来处理异步方法。异步执行器是通过实现Spring框架的TaskExecutor接口来定义的,它负责创建和管理线程池,用于执行异步任务。这里指定了自定义的处理器

2:在启动类上添加@EnableAsync注解

@SpringBootApplication
@EnableAsync         //扫描异步
@EnableScheduling    //扫描定时器
public class ScheduleApplication {
    public static void main(String[] args) {
        SpringApplication.run(ScheduleApplication.class, args);
    }
}

3:编写测试方法TEST,然后测试

@SpringBootTest(classes = GhacApplication.class)
@RunWith(SpringRunner.class)
@Slf4j
public class AsyncTaskTest {

    @Resource
    private AsyncTask asyncTask;

    /**
     * 测试异步线程池
     */
    @Test
    public void task(){
        for (int i = 0; i < 1000; i++) {
            asyncTask.myAsync();
        }

        /*这里睡眠是为了等待异步执行完成,
        如果不等待,在异步还没有执行完成就会直接关闭线程池,
        导致任务没有执行完成*/
        try {
            Thread.sleep(3000); // 毫秒值,给异步任务足够的时间来完成操作
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

执行结果

注意:如果是写测试类测试需要使用sleep()方法,但在项目启动后不用如此,因为线程池一直是开启状态(也可手动关闭)

@Async失效场景
  • 异步方法使用static修饰

  • 异步类没有使用@Component、@Service等注解,导致spring无法扫描到异步类

  • 调用的异步方法,不能为同一个类的方法(包括同一个类的内部类)。PS:因为Spring在启动扫描时会为其创建一个代理类,而同类调用时,还是调用本身的代理类的,所以和平常调用是一样的

  • 类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象

  • 如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解

  • 在Async 方法上标注@Transactional是没用的。 在Async 方法调用的方法上标注@Transactional 有效。

参考:SpringBoot对多线程的集成及异步调用,ThreadPoolTaskExecutor类 - 灰信网(软件开发博客聚合)

 如果想深入了解更多,可以看这篇👆

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值