Spring 线程池扩展指南:自定义配置、队列策略和拒绝策略 (springernature)
SpringBoot使用线程池
线程池是一种线程使用模式。 线程过多会带来额外的开销,其中包括创建销毁线程的开销、调度线程的开销等等,同时也降低了计算机的整体性能。 线程池维护多个线程,等待监督管理者分配可并发执行的任务。 这种做法,一方面避免了处理任务时创建销毁线程开销的代价,另一方面避免了线程数量膨胀导致的过分调度问题,保证了对内核的充分利用。 使用线程池,有几点好处: Java开发,我们使用JDK环境,开发框架基本都是Spring全家桶。 线程池的基础原理都在JDK中,JDK1.5新增线程池相关类,在核心jar包 中, 下面。 看一下jdk中线程池继承关系类图:JDK中,使用 ThreadPoolExecutor 给创建了几个不同功能种类的线程池,可以调出来看看: 看一下都有什么特点: 从上面可以看出他们各有各的特点,但是阿里巴巴开发守则却不推荐使用以上线程池,因为它们可能会对服务资源的浪费,所以推荐使用通过ThreadPoolExecutor自定线程池。 Spring中将Java中的线程池进行了封装,而且提供了默认实现,也能自定义线程池,我一般都用Spring中的线程池包。 Spring中的线程池和JDK中的基本一样,在 包下面。 和JDK中对应的,Spring的顶层接口是 TaskExecutor ,它实现了JDK中的 Executor 接口。 Spring中常用的线程池是 ThreadPoolTaskExecutor ,它是是借助于JDK并发包中的 来实现的。 要想使用线程池,先了解一下线程池中的一些参数: 因为我们常用的是 ThreadPoolExecutor 线程池,所以去这个类中找。 上面配置了线程池,并生成了线程池bean,交给了Spring容器管理,使用时注入即可使用。 SpringBoot线程池自动装配在 spring-boot-autoconfigure 这个jar中,在 类中。 自动装配条件:当往线程池中提交新任务时,线程池主要流程如下:核心线程数 -> 线程队列 -> 最大线程数 -> 拒绝策略 所以使用线程池,需要注意:
SpringBoot如何整合Hystrix
在配置文件中加入如下配置:
将全局的默认超时时间由1s修改为3s,但是配置未起作用。
Archaius 默认支持两种方式来加载本地的配置文件:
使用注解的方式,为方法添加hystrix断路器。
在resources\中进行配置:
使用Hystrix后,配置均会在#AbstractCommand 类中组装。
[图片上传失败...(image-a9070e-77)]
注:需要注意的是,虽然在3个地方设置了 超时时间。但是只有4000ms的超时时间生效。
1. hystrix配置的优先级是怎么样的呢? 2. 如何为某个方法配置不同的hystrix策略?
优先级从低到高的配置:
注:全局配置是default的配置,而实例配置为commandKey配置。
默认情况下,Hystrix会使用 类名作为CommandGroup ,会使用 方法名作为CommandKey。 可以使用commandKey进行个性化的配置。参考【1.3 如何使用】
[图片上传失败...(image-95f991-77)]
表示()的执行时的策略,有以下两种策略:
以下属性控制() 如何执行,这些属性对隔离策略THREAD 和SEMAPHORE 都起作用。
此属性设置从调用线程允许()方法允许的最大并发请求数,如果达到最大的并发量,则接下来的请求都会被拒绝并且抛出异常。
控制断路器的行为。
默认值20。若是在10s(窗口时间)内,只收到19个请求且都失败了,则断路器也不会开启。
断路器跳闸后,在此值的时间内,hystrix会拒绝新的请求,只有过了这个时间,断路器才会打开闸门。默认值5000ms
设置失败百分比的阈值,如果失败比率超过这个值,则断路器跳闸并且进入fallback状态。默认值:50
如果这个属性true强制断路器进入开路(跳闸)状态,它将拒绝所有请求。 此属性优先于。默认值false
如果设置true,则强制使断路器进行关闭状态,此时会允许执行所有请求,无论是否失败的次数达到值。默认值:false。
捕获和HystrixCommand以及HystrixObservableCommand执行信息相关的配置属性。
Hystrix保留断路器使用和发布指标的时间。默认值
% == 01 如/10、/20是正确的配置,但是/7错误的。默认值:10 注:在高并发的环境里,每个桶的时间长度建议大于100ms。
该属性控制HystrixCommand使用到的Hystrix的上下文。
默认值:true
表示是否开启日志,打印执行HystrixCommand的情况和事件。默认值true
设置请求合并请求。
默认值_VALUE
默认值:10
是否对() 和 ()开启请求缓存 默认值:true
默认值:10
在1.5.9中添加。此属性设置最大线程池大小。这是在不开始拒绝HystrixCommands的情况下可以支持的最大并发数量。请注意,此设置仅在您设置时生效allowMaximumSizeToDivergeFromCoreSize。在1.5.9之前,核心和最大尺寸始终相等。 默认值:10
设置最大的BlockingQueue队列的值。如果设置-1,则使用SynchronousQueue队列(无限队列)。如果设置正数,则使用LinkedBlockingQueue队列。默认值:-1
因为maxQueueSize值不能被动态修改,所有通过设置此值可以实现动态修改等待队列长度。即等待的队列的数量大于queueSizeRejectionThreshold时(但是没有达到maxQueueSize值),则开始拒绝后续的请求进入队列。 默认值:5注:如果设置-1,则属性不启作用。
设置线程空闲多长时间后,释放(maximumSize-coreSize )个线程。默认值1(分钟)
设置allowMaximumSizeToDivergeFromCoreSize值为true时,maximumSize才有作用 默认值:false
官网——Hystrix的参数配置 Hystrix常用功能介绍 Hystrix源码解析--从原生的lib开始使用hystrix(一)
线程池工作原理
管理线程,当线程执行完当前任务,不会死掉而是 会从队列里面取 1.降低系统资源消耗。 通过复用已存在的线程,降低线程创建和销毁造成的消耗; 2.提高响应速度。 当有任务到达时,无需等待新线程的创建便能立即执行; 3.提高线程的可管理性。 线程是稀缺资源,如果无限制的创建,不仅会消耗大量系统资源,还会降低系统的稳定性,使用线程池可以进行对线程进行统一的分配、调优和监控。 本文主要是围绕 ThreadPoolExecutor(线程池框架的核心类)的构造方法参数 展开 线程池中的核心线程数。 当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行。 额外最大线程数。 上面说到任务数足够多,且使用的是有界队列,如果当前阻塞队列满了,且继续提交任务,则创建新的线程执行任务,首先从队列里面取,如果队列里面的消息执行完毕,等下一定时间,额外线程自动销毁。 线程空闲时的存活时间。 默认情况下,可以理解成额外最大线程数没活干了,额外线程线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。 但是如果调用了allowCoreThreadTimeOut(boolean)方法,keepAliveTime参数也会起作用,直到线程池中的线程数为0。 keepAliveTime参数的时间单位。 任务缓存队列,用来存放等待执行的任务。 如果当前线程数为corePoolSize,继续提交的任务就会被保存到任务缓存队列中,等待被执行。 一般来说,这里的BlockingQueue有以下三种选择: * SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态。 因此,如果线程池中始终没有空闲线程(任务提交的平均速度快于被处理的速度),可能出现无限制的线程增长。 * LinkedBlockingQueue:基于链表结构的阻塞队列,如果不设置初始化容量,其容量为_VALUE,即为无界队列。 因此,如果线程池中线程数达到了corePoolSize,且始终没有空闲线程(任务提交的平均速度快于被处理的速度),任务缓存队列可能出现无限制的增长。 * ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务。 线程工厂,创建新线程时使用的线程工厂。 任务拒绝策略,当阻塞队列满了,且线程池中的线程数达到maximumPoolSize,如果继续提交任务,就会采取任务拒绝策略处理该任务,线程池提供了4种任务拒绝策略:*AbortPolicy :丢弃任务并抛出RejectedExecutionException异常,默认策略;*CallerRunsPolicy :由调用execute方法的线程执行该任务; *DiscardPolicy :丢弃任务,但是不抛出异常; *DiscardOldestPolicy :丢弃阻塞队列最前面的任务,然后重新尝试执行任务(重复此过程)。 * 当然也可以根据应用场景实现 RejectedExecutionHandler 接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。 总结下上诉参数:假设corePoolSize为10 ,maximumPoolSize为10,线程空闲时的存活时间为60s,队列采用的是有界队列ArrayBlockingQueue 设置阈值200,使 用拒绝策略 , 当前2000个任务提交过来 流程如下图 参数案例描述: 当前2000笔 任务进来,10个核心线程去处理,剩下的1990任务队列里面放200个。 剩下的1790个任务。 队列塞满会去创建10个额外线程和核心线程一起去 去执行剩下的1780个任务。 当还有剩下任务处理不了就会触发任务拒绝策略 。 当前220笔 任务进来,10个核心线程去处理,剩下的210任务队列里面放200个。 剩下的10个任务。 队列塞满会去创建10个额外线程 去执行队列放不下的任务。 当额外线程和核心线程处理完队列里面的队列。 没有任务可执行时,额外线程会等待我们设置的keepAliveTime,还是没有任务的情况下,就会被回收了 。 以上是绝对理想的状况下。 由参数可知 核心线程 和额外线程值是相同的,额外线程被回收时间是0,采用的是无界队列。 默认采用的拒绝策略为 AbortPolicy。 分析得 核心线程和额外线程处理不过来得情况,会一直往队列里面放任务。 可能存在的问题:队列过大 导致内存溢出 OOM 当任务量足够大,超过队列。 交由额外线程处理。 就会创建过多线程。 可能存在问题:特殊场景下,线程过多可能会导致系统奔溃。 cpu负载过高。 1.具体解决方案 根据业务系统而定: 华瑞批量查证举例:定时任务CZJZRW001每隔2min 轮询一次 会从业务表verifycationTask 中 查询出待处理和处理中的状态的任务 根据表中的查证类型 分流到具体的 反欺诈异步查证 ,还款查证,充值查证,贷款查证 。 具体查证根据处理结果更新verifycationTask表查证状态。 处理成功 或者失败的定时任务无法再次轮询。 这样就不需要考虑以上场景。 使用线程池的情况下核心线程,额外线程处理不过来且队列已满使用DiscardPolicy拒绝不抛异常策略,即可满足该业务场景。 类结构如下图2.思路 可以实现 RejectedExecutionHandler接口 自定义拒绝策略 将被拒绝的任务信息缓存到磁盘,等待线程池负载较低 从磁盘读取重新提交到任务里面去执行
若对本页面资源感兴趣,请点击下方或右方图片,注册登录后
搜索本页相关的【资源名】【软件名】【功能词】或有关的关键词,即可找到您想要的资源
如有其他疑问,请咨询右下角【在线客服】,谢谢支持!
相关文章
- 通过 10个引人注目的海报模板,让您的信息脱颖而出
- 10 个激动人心的海报模板,让您释放您的创造力 (激动人心的事例)
- 创造无限的机会:大学为你的未来打开了一扇门,提供无数的机遇和途径 (创造无限世界)
- 踏上领袖之路:大学培养未来的领导者,发展你的技能和自信心 (踏上领袖之路英文)
- 获得竞争优势:大学文凭是职场成功和个人成就的垫脚石 (企业如何利用信息技术获得竞争优势)
- 点燃你的好奇心:大学是一个探索思想、挑战观念和寻求真理的场所 (点燃你的好奇心)
- 超越界限:大学是一片广阔的知识和成长的领域,扩展你的视野 (超越界限之人)
- 点亮你的激情:在大学中追随你的兴趣,培养你的才能 (点亮你的激情是什么歌)
- 探索无限可能:开启大学之旅,点燃你的抱负 (探索无限可能下句)
- 迈向成功之路:释放大学潜力,塑造你的未来 (迈向成功之路必定荆棘丛生是谁说的?)
发表评论
评论列表
- 这篇文章还没有收到评论,赶紧来抢沙发吧~