Java并发编程基础(二)——多线程——线程池的应用

1.为什么要使用线程池?

主要可以归纳出以下几点:

  1. 降低资源消耗:频繁创建、销毁线程的开销很大。创建需要分配内存、初始化占空间、调度资源,销毁时又需要将分配的各类资源回收。如果能够复用早已经存在的一些线程来处理多个任务,那么就能有效地降低频繁创建销毁线程带来的开销;

  2. 提高响应速度:线程池中已有空闲线程时,任务无需等待线程创建;

  3. 控制并发规模:限制最大线程数,通过maximumPoolSize和队列容量,避免线程数量爆炸。若是允许无限线程处理请求,在高并发的情况下,可能会导致服务器资源耗尽崩溃。使用线程池就能够通过队列排序和拒绝策略进行限流。

  4. 提供对线程的灵活管理:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控(可以通过继承ThreadPoolExecutor并重写beforeExecute()afterExecute()等方法,实现任务监控和日志记录等)。

2.Java线程池的使用

在java中与并发编程相关的类和接口集中在java.util.concurrent(具体concurrent下有哪些常用的实现类可以参考搞定Java多线程:concurrent并发包梳理_多线程concurrent包-CSDN博客)下,而其中与线程池相关的最核心的即ExecutorService接口、 Executor 接口以及ThreadPoolExecutor 实现类。他们之间的关系如下:

最核心的即ThreadPoolExecutor实现类。

其中构造函数的具体介绍和实现原理可以参考:

https://blog.csdn.net/u013541140/article/details/95225769文章浏览阅读10w+次,点赞1.2k次,收藏8.5k次。熟悉Java多线程编程的同学都知道,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了。_java线程池 https://blog.csdn.net/u013541140/article/details/95225769

除了通过ThreadPoolExecutor手动实现线程池,Executors也为我们封装好了四类常见的功能线程池,分别是FixedThreadPool(定长线程池)、ScheduledThreadPool(定时线程池)、CachedThreadPool(可缓存线程池)和SingleThreadExecutor(单线程化线程池)。除了上述的四种线程池,还有一种基于forkjoin实现的WorkStealingPool线程池,

具体的实现以及应用场景也可参照上文。上文也讲述了在实际开发,面对较为复杂的场景为什么推荐使用ThreadPoolExector直接实现线程池而不是用Executors提供的高度封装的线程池。

本文举一个简单的多线程在Java领域的应用。

3.Java多线程的应用举例

多线程技术可以被应用在高并发异步任务处理、资源调度优化、离线任务等多种类型的任务中。下面我们以电商平台的订单支付后异步处理流程为例,说明多线程在实际生产环境中的典型应用。

3.1场景描述

在电商系统中,用户完成支付后,系统需执行以下操作:

  1. 更新订单状态为“已支付”;

  2. 通知库存服务扣减库存;

  3. 触发用户积分赠送;

  4. 发送支付成功短信/邮件;

  5. 记录操作日志至数据库。

若采用单线程同步执行,用户需等待所有操作完成才能得到响应,可能导致接口延迟高、吞吐量低。通过多线程异步处理,可将非核心链路任务并行化,提升系统性能。

3.2 可能可行的实施方案

线程池管理任务

使用ExecutorService创建线程池(如FixedThreadPoolCachedThreadPool),分离主线程与异步任务:

@Autowired
private ThreadPoolTaskExecutor taskExecutor; // Spring管理的线程池

public void handlePostPayment(Order order) {
    // 主线程快速完成核心操作(更新订单状态)
    orderService.updateStatus(order.getId(), PAID);
    
    // 提交异步任务到线程池
    taskExecutor.execute(() -> notifyInventory(order));     // 扣减库存
    taskExecutor.execute(() -> grantPoints(order.getUser())); // 赠送积分
    taskExecutor.execute(() -> sendPaymentNotification(order)); // 发送通知
    taskExecutor.execute(() -> logOperation(order));       // 记录日志
}

任务隔离与容错

  • 重试机制:对依赖外部服务(如短信服务)的任务,采用线程池配合重试框架(如Spring Retry)实现失败重试,避免因单次调用失败阻塞整体流程。

  • 超时控制:通过FutureCompletableFuture设置任务超时时间,防止线程因外部服务故障被长时间占用。

线程安全与数据一致性

  • 共享资源保护:例如库存扣减需使用分布式锁(如Redis RedLock)或数据库乐观锁,避免超卖。

  • 异步任务幂等:通过唯一业务ID(如订单号)确保重复提交的任务仅生效一次。

扩展应用场景

  • 分布式定时任务:如每日凌晨批量生成财务报表,多线程并行计算不同业务线的数据。

  • 实时监控与告警:后台线程周期性采集微服务健康状态(如CPU、内存),异常时触发告警通知。

  • 数据迁移与ETL:多线程分片处理大规模数据迁移任务,如将历史订单从MySQL迁移至HBase。

参考

搞定Java多线程:concurrent并发包梳理-CSDN博客

 Java 多线程:彻底搞懂线程池_java线程池-CSDN博客

Java多线程(超详细!)_java 多线程-CSDN博客 

......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

新停浊酒杯

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

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

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

打赏作者

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

抵扣说明:

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

余额充值