Spring异步线程池的问题

news2024/11/23 18:51:59

今天看一视频,提到说 Spring默认的异步线程池比较简单,每次执行异步任务,都会新建一个线程进行处理,不会重复利用,所以在用Spring框架开发的时候,需要自定义异步线程池。第一次听到这个说法。遂开始百度。

百度 “Spring 默认的异步线程池的配置”

不到三秒看到了这么一个博客: https://www.cnblogs.com/zhaoyuan72/p/16347289.html

看到了 原文地址是从知乎来的,遂跳转到知乎:https://zhuanlan.zhihu.com/p/346086161。

我这个人有个毛病,干什么都想看到最原始的那个东西,比如听歌就要听原唱,不听改编翻唱,好吧,其实这样没必要。

作者开篇提到

上一篇分享了JDK自带的线程池 ThreadPoolExecutor 的配置和参数详解,然而我们实际开发中更多的是使用SpringBoot来开发,Spring默认也是自带了一个线程池方便我们开发,它就是ThreadPoolTaskExecutor,接下来我们就来聊聊Spring的线程池吧。

就是说 JDK自带的线程池是 ThreadPoolExecutor,而Spring框架又自我封装了一个线程池 ThreadPoolTaskExecutor。说实话,这个思想就是这样,JDK本身有自带的东西,很多框架觉得JDK的东西不好,都会自己二次改造,再来一个。

比如说JDK默认的序列化机制速度慢,生成的字节占用空间大,用的是java.io.ObjectInputStream 和 ObjectOutputStream。所以一般我们也不会用JDK的序列化机制,比如前后端交互我们用JSON,JSON又可以用FastJson或者Jackson等等。其他的场景如一个RPC框架我们可以用 Java 下面的最快的序列化工具 Kyro。(举例可能不恰当,但是就是这么个意思)

再比如说 Spring也有些东西,可能其他框架觉得它不太好,也会自己写一个。比如 StringUtils 这个类,一般开发中可能都会用 common.lang3的StringUtils,MP也会封装自己的 StringUtils,Hutool也会封装自己的StringUtils。

突然就理解了 common.lang 和 common.lang3 以及 fastjson 和fastjson2 的关系了。
commons.lang3 就是 common.lang 的3.x版本, 但是应该是一次大版本升级,所以重新搞成了一个artifact,fastjson2也是如此。
common.lang3的一个版本一定是从3.x开始的。fastjson2也一定是从2.x开始的

我们大致看一下 ThreadPoolExecutor。
参考了这篇文章。
https://blog.csdn.net/cy973071263/article/details/131484311 。

大致看完这个,开始看Spring的 ThreadPoolTaskExecutor。就看之前知乎的那一篇文章,作者先说的是 SimpleAsyncTaskExecutor,

在这里插入图片描述

在这里插入图片描述

于是我决定执行自己的demo

在这里插入图片描述

发现几个问题
1.没有如作者博客一样,我的demo线程复用了,没有一直创建,但是默认好像是8个线程
2.没有如博客作者一样打印出来 SimpleAsyncTaskExecutor 这个类

于是,去看了一下博客的日期,距今(2024年0925日)已经三年多了,Spring我目前用的都是5.3的版本了

在这里插入图片描述
看到了这个,可以去翻源码了,猜想是不是新版本Spring 默认的 concurrencyLimit 是8

在这里插入图片描述

看源码,全局搜 concurrencyLimit。

在这里插入图片描述
卧槽,那岂不是沙雕了。

又看一下我之前设置 的定时默认线程数是 8,但是我已经全部注释掉了呀
在这里插入图片描述

于是,开始去找新的博客看看。这次搜索的词条是:

Spring默认的异常线程池 SimpleAsyncTaskExecutor
并刻意去看2023、2024年的帖子,发现基本都说 默认的异步线程池 SimpleAsyncTaskExecutor 线程确实不可以重用。
感觉还是我本身项目代码的问题,我应该在某个地方设置了 最多可用线程数为8或者怎么样。

尝试1:既然注释没有效果,直接删掉 SchedulingConfig 这个类
发现还是一样的。

尝试2:去其他项目,运行这个demo
发现还是一样的 8 个线程在重用

则现在又有1种猜测
我加了 @Async 注解,到底有没有用 SimpleAsyncTaskExecutor 线程池

突然想起来了之前看 一个项目做的笔记。
说 @Async 注解的原理是

在这里插入图片描述
发现这里的 核心线程数确实是8 ,md破案了。
感觉根本没有用 SimpleAsyncTaskExecutor。

再去问 文心一言

当在Spring应用中使用@Async注解来声明异步方法时,如果没有明确指定线程池,那么默认情况下会使用SimpleAsyncTaskExecutor ,那如果是SpringBoot应用呢

在Spring Boot应用中,当使用@Async注解来声明异步方法时,如果没有明确指定线程池,其默认行为会根据Spring Boot的版本有所不同。

早期版本

在Spring Boot的某些早期版本中(通常指2.1之前的版本),如果没有特别配置,@Async注解标注的异步方法可能会默认使用SimpleAsyncTaskExecutor。这个执行器每次执行一个任务时都会创建一个新的线程,而不是复用现有的线程,这可能导致在高并发场景下创建大量线程,进而引发性能问题。

2.1及以后版本

从Spring Boot 2.1版本开始,情况发生了变化。在Spring Boot 2.1及以后的版本中,@Async注解默认使用的线程池不再是SimpleAsyncTaskExecutor,而是ThreadPoolTaskExecutor。这意味着,如果没有特别配置,异步方法将会在一个线程池中执行,该线程池具有核心线程数、最大线程数、队列容量等配置参数。

具体来说,ThreadPoolTaskExecutor的默认配置通常包括:

  • 核心线程数:8
  • 最大线程数Integer.MAX_VALUE
  • 队列容量Integer.MAX_VALUE(使用LinkedBlockingQueue
  • 空闲线程保留时间:60秒
  • 线程池拒绝策略AbortPolicy(当线程池饱和时,尝试执行新任务会抛出异常)

自定义配置

尽管Spring Boot提供了默认的线程池配置,但在实际应用中,根据业务需求和系统负载,这些默认配置可能需要调整。开发者可以通过在application.ymlapplication.properties文件中添加相应的配置属性来自定义线程池的行为。

例如,要调整核心线程数、最大线程数和队列容量,可以在application.properties中添加如下配置:

spring.task.execution.pool.core-size=10
spring.task.execution.pool.max-size=20
spring.task.execution.pool.queue-capacity=50

或者,在application.yml中添加类似配置:

spring:
  task:
    execution:
      pool:
        core-size: 10
        max-size: 20
        queue-capacity: 50

结论

因此,在Spring Boot应用中,如果没有明确指定线程池,@Async注解默认使用的线程池从Spring Boot 2.1版本开始是ThreadPoolTaskExecutor,而不是SimpleAsyncTaskExecutor。这提供了更好的线程复用和资源管理能力,但在实际应用中仍需要根据需要进行适当的配置调整。

再点进去

在这里插入图片描述

在这里插入图片描述

确实需要自定义异步线程池。

我之前的demo默认走的是 ThreadPoolTaskExecutor的配置。

但是这里我就好奇了,那在Spring 框架里面默认的线程池配置是通过哪个类实现的???

在这里插入图片描述

在这里插入图片描述

ai得出这个答案,我就不单独去验证Spring框架下面,@Scheduled 注解的行为了,毕竟现在都是基于SpringBoot开发。

如何自定义异步线程池,参考了 https://blog.csdn.net/kdzandlbj/article/details/139046266 的第二种方式。

在这里插入图片描述

异步线程池定义如图所示

在这里插入图片描述

启动项目,发现确实生效了,最大的执行线程就是5

在这里插入图片描述

但是这里有个问题,为什么 springBoot(这应该是SpringBoot决定的吧)的log打印,好像是打印 线程名.subtring(str.length-15)

在这里插入图片描述
稍等讨论这个问题,我想知道这个

executor.setThreadNamePrefix("AsyncThreadPool-t-");

线程工厂是如何把这个 线程名前缀加在线程上的.
首先要认知到一个问题,任何框架的线程池肯定都是基于JDK线程池的,而JDK线程池里面的线程都是由线程工厂创建的 也就是 ThreadFactory。所以,直接去找线程工厂。

在这里插入图片描述

在这里插入图片描述
点进去 CustomizableThreadFactory 看一看

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

再来说 SpringBoot输出的为什么是 substring的ThreadName。

在这里插入图片描述
找了一下感觉乱七八糟的,没什么章法,直接百度吧。

百度了一圈没有说什么源码的,都是说配置的,没劲,我自己debug看吧。

在这里插入图片描述

在这里插入图片描述

但是代码到下面就走完了。

在这里插入图片描述

事前先百度了一下。
在这里插入图片描述

ok,到这里 线程日志打印截断15个字符就结束了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2197931.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

迷你世界表白神器爱心脚本lua

--迷你世界专用爱心表达公式 local a,angle,count,id30,0,0,math.random(668, 681) -- 根据需要调整θ的遍历范围和步长 while true do angle angle0.01 local ra*(math.sin(angle)*(math.sqrt(math.abs(math.cos(angle)))/(math.sin(angle)1.4)-2)2) if r>10…

动手学深度学习59 双向循环神经网络

1. 双向循环神经网络 视频:https://www.bilibili.com/video/BV12X4y1c71W/?p2&spm_id_frompageDriver&vd_sourceeb04c9a33e87ceba9c9a2e5f09752ef8 课件:https://courses.d2l.ai/zh-v2/assets/pdfs/part-3_7.pdf 课本: https://zh-…

机器学习K近邻算法——分类问题K近邻算法示例

针对“数据8.1”,讲解分类问题的K近邻算法,以V1(转型情况)为响应变量,以V2(存款规模)、V3(EVA)、V4(中间业务收入)、V5(员工人数&…

【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则

文章目录 C 继承详解:初阶理解与实战应用前言第一章:继承的基本概念与定义1.1 继承的概念1.2 继承的定义 第二章:继承中的访问权限2.1 基类成员在派生类中的访问权限2.2 基类与派生类对象的赋值转换2.2.1 派生类对象赋值给基类对象2.2.2 基类…

多端同步的收银系统源码

随着经济的不断发展,很多门店越来越趋向连锁品牌化,收银系统自然也成为很多连锁门店必不可少的软件工具。希望通过一套软件可以帮助门店解决门店线下销售、会员管理、连锁多门店管理、线下线上一体化、商品库存管理等难题实现降本增效,为了方…

MySQL连接查询:联合查询

先看我的表结构 emp表 联合查询的关键字(union all, union) 联合查询 基本语法 select 字段列表 表A union all select 字段列表 表B 例子:将薪资低于5000的员工, 和 年龄大于50 岁的员工全部查询出来 第一种 select * fr…

大模型微调技术之 LoRA:开启高效微调新时代

一、LoRA 简介 LoRA,即低秩适应(Low-Rank Adaptation),是一种用于微调大型语言模型的技术,旨在以较小的计算资源和数据量实现模型的快速适应特定任务或领域。 LoRA 方法通过引入低秩近似的思想,对大型预训…

NFS共享文件系统(将文件目录挂载到别的机器上)

我们创建的磁盘是否都必须挂载到本机上?并不是。在 Linux 和其他操作系统中,有一种叫做 NFS(网络文件系统)的工具,它允许跨网络共享文件系统资源。通过使用 NFS,我们可以将多个客户端服务器的数据目录挂载到…

Java中常见的等待唤醒机制及实践

JDK自带的等待唤醒机制 在Java中,有一个JDK维度的等待唤醒机制。Object类的wait和notify,notifyAll 需要在synchronized同步代码块内并且对象必须获取到锁才能调用。否则会抛IllegalMonitorStateException异常。 当线程在尝试获取锁时失败,会被封装成节…

Mybatis-plus做了什么

Mybatis-plus做了什么 Mybatis回顾以前的方案Mybatis-plus 合集总览:Mybatis框架梳理 聊一下mybatis-plus。你是否有过疑问,Mybatis-plus中BaseMapper方法对应的SQL在哪里?它为啥会被越来越多人接受。在Mybatis已经足够灵活的情况下&…

《强烈推荐一个强大的书签管理工具》

在信息爆炸的时代,我们每天都会浏览大量的网页,收藏各种各样的书签。然而,随着书签数量的增加,管理起来也变得越来越困难。这时,一个强大的书签管理工具就显得尤为重要。今天,我要向大家推荐一款备受好评的…

EtherCAT学习笔记

文章目录 前言一、EtherCAT介绍二、EtherCA系统组成2.1 ESC(EtherCAT从站控制器)2.2 从站控制微处理器2.3 物理层器件2.4 其它应用层器件 三、EtherCAT数据帧结构3.1 寻址方式3.2 时钟3.3 通信模式 四、状态机和通信初始化五、应用层协议六、ESC概述6.1 EtherCAT从站控制芯片6.…

基于SpringBoot+Vue+MySQL的美食信息推荐系统

系统展示 用户前台界面 管理员后台界面 系统背景 在数字化时代,随着人们对美食文化的热爱与追求不断增长,美食信息推荐系统成为了连接食客与美食之间的重要桥梁。面对海量的美食信息,用户往往难以快速找到符合个人口味和需求的美食。因此&…

Java-数据结构-Lambda表达式 (✪ω✪)

文本目录: ❄️一、背景: ➷ 1、Lambda表达式的语法: ➷ 2、函数式接口: ❄️二、Lambda表达式的基本使用: ➷ 1、语法精简: ❄️三、变量捕获: ❄️四、Lambda在集合中的使用: …

Chromium 中js navigator对象c++实现分析

一、Navigator 对象 Navigator 对象包含有关浏览器的信息。 前端测试例子&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>接口测试</title> </head> <body><div id"example&q…

爱心表达公式

脚本公式 local r (math.sin(angle) * math.sqrt(math.abs(math.cos(angle)))) / (math.sin(angle) 1.4) - 2 * math.sin(angle) 2

IOT-Tree连接西门子PLC S7 200 Smart竟然如此简单

最近一个项目需要把用户现场控制柜接入到云端&#xff0c;控制柜使用西门子PLC Smart 200 SR40型号&#xff0c;已经运行多年&#xff0c;PLC通过以太网接口对接一个触摸屏。 按照我以往的经验&#xff0c;觉得触摸屏以太网接口已经被占用&#xff0c;那么只能通过剩余的RS485…

通过一个实际的例子,介绍 Java 的自动装箱与拆箱机制

Java 中 1000 1000 返回 false&#xff0c;但 100 100 返回 true&#xff0c;这一现象背后隐藏了 Java 对于对象和基本类型的内存管理机制。为了理解这个现象&#xff0c;我们需要从 Java 的自动装箱与拆箱机制、对象引用和数值缓存策略等角度深入探讨。让我们一步一步通过 J…

电脑怎么卸载软件?学会这6个卸载软件技巧就够了(精选)

电脑怎么卸载软件&#xff1f;在日常的办公生活中&#xff0c;我们需要下载一些工具来辅助工作&#xff0c;当不需要这些工具的时候&#xff0c;我们就需要卸载这些软件了。很多小伙伴表示卸载软件卸载不干净&#xff0c;还是回残留一些文件&#xff0c;或者是卸载不了&#xf…

Verilog开源项目——百兆以太网交换机(九)表项管理模块设计

Verilog开源项目——百兆以太网交换机&#xff08;九&#xff09;表项管理模块设计 &#x1f508;声明&#xff1a;未经作者允许&#xff0c;禁止转载 &#x1f603;博主主页&#xff1a;王_嘻嘻的CSDN主页 &#x1f511;全新原创以太网交换机项目&#xff0c;Blog内容将聚焦整…