0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Spring 的线程池应用

科技绿洲 来源:Java技术指北 作者:Java技术指北 2023-10-13 10:47 次阅读

我们在日常开发中,经常跟多线程打交道,Spring 为我们提供了一个线程池方便我们开发,它就是 ThreadPoolTaskExecutor ,接下来我们就来聊聊 Spring 的线程池吧。


使用@Async声明多线程

SpringBoot 提供了注解 @Async 来使用线程池, 具体使用方法如下:

  1. 在启动类(配置类)添加@EnableAsync来开启线程池
  2. 在需要开启子线程的方法上添加注解 @Async

下面是一个简单的例子:

@Component
@EnableAsync
@EnableScheduling
public class ScheduleTask {

    @Async
    @Scheduled(fixedRate = 2000)
    public void testAsync1() {
        try {
            Thread.sleep(6000);
            System.out.println(LocalDateTime.now() + "--线程1:" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Async
    @Scheduled(cron = "*/2 * * * * ?")
    public void testAsync2() {
        try {
            Thread.sleep(1000);
            System.out.println(LocalDateTime.now() + "--线程2:" + Thread.currentThread().getName());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

启动项目,得到如下日志结果:

图片

可以发现在当前环境下 task-${id} 这个 id 并不是一直增长的,而是一直在复用 1-8。这个时候可能就会有的小伙伴们会比较好奇,默认的不是 SimpleAsyncTaskExecutor 吗?为什么从日志打印的效果上看像是一直在复用 8 个线程,难道用的是 ThreadPoolTaskExecutor?

原因是 SpringBoot2.1.0 版本后,新增了 TaskExecutionAutoConfiguration 配置类。其中声明的默认线程池就是 ThreadPoolTaskExecutor 。而 @Async 在选择执行器的时候会先去 IOC 容器中先找是否有 TaskExecutor 的 Bean对象,所以在当前版本 SpringBoot 中,@Async 的默认 TaskExecutor 是 ThreadPoolTaskExecutor。

线程池配置

在 SpringBoot 项目中,我们可以在 yaml 或者 properties 配置文件中配置,或者使用 @Configuration 配置,下面演示配置方法。

  1. application.properties配置文件中配置
# 核心线程池数
spring.task.execution.pool.core-size=5
# 最大线程池数
spring.task.execution.pool.max-size=10
# 任务队列的容量
spring.task.execution.pool.queue-capacity=5
# 非核心线程的存活时间
spring.task.execution.pool.keep-alive=60
# 线程池的前缀名称
spring.task.execution.thread-name-prefix=test-task-
  1. 配置类中配置
@Bean(name = "myThreadPoolTaskExecutor")
public ThreadPoolTaskExecutor getMyThreadPoolTaskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    int i = Runtime.getRuntime().availableProcessors();
    taskExecutor.setCorePoolSize(i * 2);
    taskExecutor.setMaxPoolSize(i * 2);
    taskExecutor.setQueueCapacity(i * 2 * 100);
    taskExecutor.setKeepAliveSeconds(60);
    taskExecutor.setThreadNamePrefix("my-task-");
    taskExecutor.initialize();
    return taskExecutor;
}

拒绝策略

RejectedExectutionHandler 参数字段用于配置绝策略,常用拒绝策略如下

  • AbortPolicy:用于被拒绝任务的处理程序,它将抛出RejectedExecutionException
  • CallerRunsPolicy:用于被拒绝任务的处理程序,它直接在execute方法的调用线程中运行被拒绝的任务。
  • DiscardOldestPolicy:用于被拒绝任务的处理程序,它放弃最旧的未处理请求,然后重试execute。
  • DiscardPolicy:用于被拒绝任务的处理程序,默认情况下它将丢弃被拒绝的任务。

处理流程

  1. 查看核心线程池是否已满,不满就创建一条线程执行任务,否则执行第2步。
  2. 查看任务队列是否已满,不满就将任务存储在任务队列中,否则执行第3步。
  3. 查看线程池是否已满,即就是是否达到最大线程池数,不满就创建一条线程执行任务,否则就按照策略处理无法执行的任务。

使用注意

  1. 注解的方法必须是 public 方法。
  2. 方法一定要从另一个类中调用,也就是从类的外部调用,类的内部调用是无效的,因为 @Transactional 和 @Async 注解的实现都是基于 Spring 的 AOP ,而 AOP 的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过 Spring 容器。
  3. 异步方法使用注解 @Async 的返回值只能为 void 或者 Future。

总结

上面简单介绍了 Spring 自带的线程池 ThreadPoolTaskExecutor 的配置和使用,并且讲了线程池的参数和处理流程。当然Spring提供了7个线程池的实现,感兴趣的可以自行了解~

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 文件
    +关注

    关注

    1

    文章

    540

    浏览量

    24402
  • 容器
    +关注

    关注

    0

    文章

    481

    浏览量

    21883
  • spring
    +关注

    关注

    0

    文章

    332

    浏览量

    14161
  • 线程池
    +关注

    关注

    0

    文章

    53

    浏览量

    6768
收藏 人收藏

    评论

    相关推荐

    Spring Boot如何实现异步任务

    上,用来告诉 Spring 这个方法是一个异步方法,Spring 会将这个方法的执行放在异步线程中进行。使用 @Async 注解需要满足以下条件: 需要在 Spring Boot 主类
    的头像 发表于 09-30 10:32 488次阅读

    Spring Boot虚拟线程和Webflux性能对比

    早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。
    发表于 09-24 14:54 294次阅读
    <b class='flag-5'>Spring</b> Boot虚拟<b class='flag-5'>线程</b>和Webflux性能对比

    java spring教程

    java spring教程理解Spring 实现原理掌握Spring IOC,AOP掌握Spring的基础配置和用法熟练使用SSH开发项目Sprin
    发表于 09-11 11:09

    什么是java spring

    什么是java springSpring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成
    发表于 09-11 11:16

    如何用ACM简化你的Spring Cloud微服务环境配置管理

    为WARNING 在开发环境中使用4核8G的机器跑数据库,而在生产中用32核96G机器跑数据库 在日常环境执行线程的最大线程数应该设置为15,而生产环境上这个值应该大一点,默认设为150 在线
    发表于 02-02 14:18

    使用阿里云ACM简化你的Spring Cloud微服务环境配置管理

    logLevel设置为INFO,生产环境里logLevel设置为WARNING在开发环境中使用4核8G的机器跑数据库,而在生产中用32核96G机器跑数据库在日常环境执行线程的最大线程数应该设置为15
    发表于 07-04 17:16

    Mybatis整合spring的思路和步骤

    代理形式中,应该从spring容器中直接获得mapper的代理对象。(4)数据库的连接以及数据库连接事务管理都交给spring容器来完成。
    发表于 11-04 09:06

    线程是如何实现的

    线程的概念是什么?线程是如何实现的?
    发表于 02-28 06:20

    线程创建的两种方法

    1. 使用内置模块在使用多线程处理任务时也不是线程越多越好,由于在切换线程的时候,需要切换上下文环境,依然会造成cpu的大量开销。为解决这个问题,线程
    发表于 03-16 16:15

    关于RT-Thread内存管理的内存简析

    :支持线程挂起。内存无空闲内存块时,申请线程会被挂起,直到有可用内存块。简单理解,就是将相同大小的内存块通过某种方式放在一起,就好比将各个内存块放在类似于水池的容器里,需要用的时候,就从这个池子里取
    发表于 04-06 17:02

    Spring认证_什么是Spring GraphQL

    Spring GraphQL 为构建在 GraphQL Java 上的 Spring 应用程序提供支持。两个团队之间的联合联合。我们的共同理念是少固执己见,更专注于全面和广泛的支持。 Spring
    的头像 发表于 08-06 14:30 519次阅读
    <b class='flag-5'>Spring</b>认证_什么是<b class='flag-5'>Spring</b> GraphQL

    Spring认证」什么是Spring GraphQL?

    这个项目建立在 Boot 2.x 上,但它应该与最新的 Boot2.4.x5 相关。 要创建项目,请转到start.spring.io并为要使用的GraphQL传输选择启动器: 启动机 运输 执行
    的头像 发表于 08-10 14:08 612次阅读
    「<b class='flag-5'>Spring</b>认证」什么是<b class='flag-5'>Spring</b> GraphQL?

    用这4招 优雅的实现Spring Boot异步线程间数据传递

    Spring Boot 自定义线程池实现异步开发相信看过陈某的文章都了解,但是在实际开发中需要在父子线程之间传递一些数据,比如用户信息,链路信息等等
    的头像 发表于 01-30 10:40 808次阅读

    Spring Boot 3.2支持虚拟线程和原生镜像

    Spring Boot 3.2 前几日发布,让我们用 Java 21、GraalVM 和虚拟线程来尝试一下。
    的头像 发表于 11-30 16:22 343次阅读

    什么是动态线程池?动态线程池的简单实现思路

    因此,动态可监控线程池一种针对以上痛点开发的线程池管理工具。主要可实现功能有:提供对 Spring 应用内线程池实例的全局管控、应用运行时动态变更线
    的头像 发表于 02-28 10:42 181次阅读