项目系统使用异步业务流程(线程池详细实现)

❤ 作者主页:李奕赫揍小邰的博客
❀ 个人介绍:大家好,我是李奕赫!( ̄▽ ̄)~*
🍊 记得点赞、收藏、评论⭐️⭐️⭐️
📣 认真学习!!!🎉🎉


  在最近做的一个BI项目中,需要调用第三方的AI大模型生成返回数据,但因为生成需要时间,所以出现了用户等待时间过长的问题。同时也要考虑到业务服务器可能面临大量请求处理,导致系统资源紧张,严重时甚至可能导致服务器宕机或无法处理新的请求。因此我们应当考虑异步化的解决方案。
 

异步化

1.介绍

同步:一件事情做完,再做另外一件事情(烧水后才能处理工作)。
异步:在处理一件事情的同时,可以处理另一件事情。当第一件事完成时,会收到一个通知告诉你这件事已经完成,这样就可以进行后续的处理(烧水时,可以同时处理其他工作。水壶上的蜂鸣器会在水烧好时发出声音,就知道水已经烧好了,可以进行下一步操作)。

 

2.异步业务流程分析

  在我们的系统中,主要是做的是一个智能BI系统,根据用户传递的数据生成图标。因此异步的流程是怎样的呢?用户在点击提交后就不需要在当前界面等待,他们可以直接回到主界面,或者继续填写下一个需要生成或分析的数据。提交完成后,他们回到主页,在主页上就可以看到图表的生成状态
  因此我们需要建立一个任务队列,将任务放到队列里面,排队等待AI服务器进行处理,那么怎么能够异步和上述要求呢?所以我们再次引入一个新的知识,“线程池”

 

线程池

1.为什么需要线程池?

1.线程的管理比较复杂(比如什么时候新增线程、什么时候减少空闲线程)
2.任务存取比较复杂(什么时候接受任务、什么时候拒绝任务、怎么保证大家不抢到同一个任务)
 

2.线程池的作用

  可以帮助你轻松管理线程、协调任务的执行过程。
扩充:可以向线程池表达你的需求,比如最多只允许四个人同时执行任务。线程池就能自动为你进行管理。在任务紧急时,它会帮你将任务放入队列。而在任务不紧急或者还有线程空闲时,它会直接将任务交给空闲的线程,而不是放入队列。

 

3.线程池的实现方式

1.在 Spring 中,我们可以利用 ThreadPoolTaskExecutor 配合 @Async 注解来实现线程池(不太建议)。
2.在 Java 中,可以使用JUC并发编程包中的 ThreadPoolExecutor,来实现非常灵活地自定义线程池。

 

4.线程池的参数

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
   
   

●第一个参数 corePoolSize (核心线程数)。这些线程就好比是公司的正式员工,他们在正常情况下都是随时待命处理任务的。如何去设定这个参数呢?比如,如果我们的 AI 服务只允许四个任务同时进行,那么我们的核心线程数应该就被设置为2-4
●第二个参数 maximumPoolSize (最大线程数)。在极限情况下我们的系统或线程池能有多少个线程在工作。就算任务再多,你最多也只能雇佣这么多的人,因为你需要考虑成本和资源的问题。假设 AI 服务最多只允许四个任务同时执行,那么最大线程数应当设置为四。
●第三个参数 keepAliveTime (空闲线程存活时间)。这个参数决定了当任务少的时候,临时雇佣的线程会等待多久才会被剔除。这个参数的设定是为了释放无用的线程资源。你可以理解为,多久之后会“解雇”没有任务做的临时工。
●第四个参数 TimeUnit (空闲线程存活时间的单位)。将 keepAliveTime 和 TimeUnit 组合在一起,就能指定一个具体的时间,比如说分钟、秒等等。
●第五个参数 workQueue (工作队列),也就是任务队列。这个队列存储所有等待执行的任务。也可以叫它阻塞队列,因为线程需要按顺序从队列中取出任务来执行。这个队列的长度一定要设定,因为无限长度的队列会消耗大量的系统资源。
●第六个参数 threadFactory (线程工厂)。它负责控制每个线程的生成,就像一个管理员,负责招聘、管理员工,比如设定员工的名字、工资,或者其他属性。
●第七个参数 RejectedExecutionHandler (拒绝策略)。当任务队列已满的时候,我们应该怎么处理新来的任务?是抛出异常,还是使用其他策略?比如说,我们可以设定任务的优先级,会员的任务优先级更高。如果你的公司或者产品中有会员业务,或者有一些重要的业务需要保证不被打扰,你可以考虑定义两个线程池或者两个任务队列,一个用于处理VIP任务,一个用于处理普通任务,保证他们不互相干扰,也就是资源隔离策略。

备注:
线程池的设计主要分为 IO 密集型和计算密集型。
  对于计算密集型的任务,它会大量消耗 CPU 资源进行计算,例如音视频处理、图像处理、程序计算和数学计算等。要最大程度上利用 CPU,避免多个线程间的冲突,一般将核心线程数设置为 CPU 的核数加一。这个“加一”可以理解为预留一个额外的线程,或者说一个备用线程,来处理其他任务,以防止以外发生。这样做可以充分利用每个 CPU 核心,减少线程间的频繁切换,降低开销。在这种情况下,对 maximumPoolSize 的设定没有严格的规则,一般可以设为核心线程数的两倍或三倍。
  而对于 IO 密集型的任务,它主要消耗的是带宽或内存硬盘的读写资源,对 CPU 的利用率不高。比如说,查询数据库或等待网络消息传输,可能需要花费几秒钟,而在这期间 CPU 实际上是空闲的。在这种情况下,可以适当增大 corePoolSize 的值,因为 CPU 本来就是空闲的。比如说,如果数据库能同时支持 20 个线程查询,那么 corePoolSize 就可以设置得相对较大,以提高查询效率。建议根据 IO 的能力来设定。在这种情况下,对 maximumPoolSize 的设定不易过大,因为IO密集型的任务对CPU要求不大,设置太大,会造成上下文切换过于频繁。

 

5.线程池的开发

  如果要创建线程池,首先需要在你的项目加上一个ThreadPoolExecutorConfig.java(线程池配置类)。

@Configuration
public class ThreadPoolExecutorConfig {
   
   

    @Bean
    public ThreadPoolExecutor t
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李奕赫揍小邰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值