写点什么

CachedThreadPool 线程池设计 / 场景案例 / 性能调优 / 场景适配(架构篇)

作者:肖哥弹架构
  • 2024-11-11
    河北
  • 本文字数:3862 字

    阅读完需:约 13 分钟

CachedThreadPool线程池设计/场景案例/性能调优/场景适配(架构篇)


在 Java 并发编程的丰富生态中,CachedThreadPool以其独特的特性脱颖而出。这种线程池动态地创建线程来处理任务,当线程空闲超过一定时间后会被回收,从而优化资源使用。CachedThreadPool适用于短生命周期的异步任务,特别是那些任务提交频率高但执行时间短的场景。它能够迅速响应新任务,同时通过重用空闲线程减少创建和销毁线程的开销。对于需要处理大量短期异步工作的开发者来说,CachedThreadPool提供了一个高效、灵活的解决方案,使得它可以在不同的并发需求下自动调整线程数量,无需手动管理线程池的大小。理解CachedThreadPool的工作原理和适用场景,对于构建高性能、响应迅速的并发应用程序至关重要。


肖哥弹架构 跟大家“弹弹” 高并发锁, 关注公号回复 'mvcc' 获得手写数据库事务代码

欢迎 点赞,关注,评论。

关注公号 Solomon 肖哥弹架构获取更多精彩内容

历史热点文章

1、CachedThreadPool 制造背景

CachedThreadPool 是 Java 并发包 java.util.concurrent 中的一种线程池实现,它根据需要动态地创建线程,并在空闲时重用已有的线程。以下是 CachedThreadPool 的设计因素:


  1. 动态线程创建

  2. CachedThreadPool 的核心特点是线程数不固定,它会根据任务的需求动态调整线程数量。当有新任务提交时,如果线程池中没有可用的空闲线程,线程池会创建一个新的线程来执行任务。

  3. 线程复用

  4. CachedThreadPool 会在空闲线程可用时重用它们。如果线程空闲超过一定时间(默认 60 秒),则会被销毁,从而释放资源。

  5. 适用于短生命周期任务

  6. CachedThreadPool 适用于执行大量短生命周期任务的场景。它能够根据任务的数量动态调整线程数量,避免频繁创建和销毁线程的开销。

  7. 提高系统性能

  8. 通过智能地管理线程资源,CachedThreadPool 提高了系统的性能和响应速度,特别是在任务数量波动较大的情况下。

  9. 资源优化

  10. CachedThreadPool 通过工作窃取算法优化资源使用,使得线程可以根据当前的任务负载动态地创建和销毁,避免了资源浪费。

  11. 灵活性和扩展性

  12. CachedThreadPool 提供了高度的灵活性和扩展性,可以根据实际需求调整线程池的行为,如自定义线程工厂和拒绝策略。

  13. 适用场景

  14. CachedThreadPool 适用于需要快速响应任务增加的场景,如高并发的 Web 应用或临时性任务处理。

  15. 注意事项

  16. 由于 CachedThreadPool 可能会创建大量线程,因此在使用时需要注意任务的执行时间和内存使用情况,以避免资源耗尽的风险。

2、CachedThreadPool 设计结构

根据需要创建新线程的线程池,对于短生命周期的异步任务非常合适。



  1. CachedThreadPool:这是可缓存的线程池,负责管理线程和任务的执行。

  2. 核心参数:包括核心线程数(0)、最大线程数(Integer.MAX_VALUE)、空闲线程存活时间(60 秒)和任务队列(SynchronousQueue)。

  3. 任务提交:任务提交到线程池执行。

  4. 直接执行任务:如果有空闲线程,直接使用空闲线程执行任务。

  5. 创建新线程执行任务:如果没有空闲线程,创建新线程执行任务。

  6. 任务执行完毕:任务执行完毕后,线程检查是否空闲超过 60 秒。

  7. 线程空闲超过 60 秒? :如果线程空闲超过 60 秒,线程将被销毁。

  8. 线程销毁:超过 60 秒空闲的线程将被销毁。

  9. 等待新任务:如果线程未超过 60 秒空闲,继续等待新任务。

  10. 线程池关闭:当线程池关闭时,所有线程将被终止。

3、CachedThreadPool 运行流程


CachedThreadPool 的运行流程:


  1. 创建 CachedThreadPool

  2. 初始化一个 CachedThreadPool 实例,这个线程池没有核心线程,但可以创建新线程来执行任务。

  3. 提交任务

  4. 客户端提交 RunnableCallable 任务到线程池。

  5. 检查空闲线程

  6. 如果有空闲线程,线程池会使用这些线程来执行新提交的任务。

  7. 创建新线程

  8. 如果没有空闲线程,线程池会创建一个新的线程来执行任务。

  9. 执行任务

  10. 线程从任务队列中取出任务并执行。

  11. 线程空闲

  12. 任务执行完毕后,线程变为空闲状态。

  13. 线程回收

  14. 如果空闲线程在一定时间内(默认 60 秒)没有任务执行,它将被回收以节省资源。

  15. 线程池关闭

  16. 当不再需要线程池时,可以调用 shutdown 方法来启动关闭序列,此时不再接受新任务。

  17. 等待任务完成

  18. 调用 awaitTermination 方法可以等待所有已提交的任务完成。

  19. 销毁所有线程

  20. 一旦所有任务执行完毕,所有剩余的空闲线程将被销毁。

4、CachedThreadPool 业务实战

4.1. 处理短期异步任务

CachedThreadPool 非常适合执行大量短期异步任务。例如,在 Web 应用中,可以用于处理用户的短期请求,如动态内容生成或小型数据查询。由于 CachedThreadPool 会根据需要动态添加线程,因此它能够灵活地应对流量高峰。


ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 10; i++) {    executorService.execute(new SimpleTask(i));}executorService.shutdown();  // 所有任务提交后关闭线程池
复制代码


在这个示例中,我们创建了一个 CachedThreadPool 并提交了 10 个简单的任务。每个任务都打印出它的 ID 和执行它的线程的名字。最后,我们关闭线程池。

4.2. 流量洪峰处理

在面对流量洪峰时,CachedThreadPool 能够快速响应,通过创建新线程来处理额外的任务。例如,一个电商平台在促销活动期间可能会遇到突然增加的订单处理请求。


ExecutorService executor = Executors.newCachedThreadPool();for (int i = 0; i < 100; i++) {    executor.execute(() -> {        // 处理订单    });}executor.shutdown();
复制代码


这个例子中,我们创建了一个 CachedThreadPool 来处理大量的订单处理任务。线程池会动态地创建线程来应对流量洪峰。

4.3. 后台任务执行

对于需要异步执行的后台任务,如日志记录、数据清理等,CachedThreadPool 可以提供高效的线程管理。


ExecutorService service = Executors.newCachedThreadPool();service.execute(() -> {    // 执行后台任务});service.shutdown();
复制代码


在这个示例中,我们创建了一个 CachedThreadPool 来执行一个后台任务。由于 CachedThreadPool 会在线程空闲超过一定时间后回收线程,因此它适合执行那些临时增加的后台任务。

注意事项

  • 控制任务提交速率:由于 CachedThreadPool 可能会创建大量的线程,因此需要控制任务的提交速率,以防止系统资源耗尽。

  • 优雅关闭线程池:使用 shutdown() 方法来优雅地关闭线程池,确保所有已提交的任务都能执行完毕。

5、CachedThreadPool 调优策略

针对 CachedThreadPool 的调优策略,以下是一些关键点:


  1. 合理设置线程池大小

  2. CachedThreadPool 默认没有核心线程,它会根据需要动态创建新线程。在任务提交速度极快时,可能会导致创建大量线程,从而耗尽系统资源。可以通过设置合理的最大线程数来避免这种情况。

  3. 选择合适的工作队列

  4. CachedThreadPool 默认使用 SynchronousQueue 作为工作队列,这意味着它不会存储任务,而是尝试将任务直接交给线程执行。如果任务生成速度超过处理速度,应考虑使用有界队列来避免内存溢出。

  5. 设置线程空闲超时时间

  6. CachedThreadPool 中的线程在空闲超过一定时间后会被终止。这个时间默认为 60 秒。根据实际业务需求调整这个时间,可以减少资源浪费。

  7. 优雅关闭线程池

  8. 使用 shutdown() 方法来优雅地关闭 CachedThreadPool,确保所有已提交的任务都能执行完毕。如果需要立即停止,可以使用 shutdownNow(),但这可能会导致正在执行的任务被中断。

  9. 监控线程池状态

  10. 监控线程池的活动线程数、任务队列长度等指标,可以帮助及时发现性能瓶颈和异常情况,并进行相应的调优。

  11. 处理任务队列中的异常

  12. 在任务执行过程中,应注意处理可能的异常,以防止线程池中的线程异常终止,影响任务的正常执行。

  13. 自定义线程工厂

  14. 通过自定义线程工厂,可以为线程设置有意义的名称,这有助于在出现问题时快速定位问题线程。

  15. 合理配置拒绝策略

  16. CachedThreadPool 在任务队列满且达到最大线程数时,会使用默认的拒绝策略(AbortPolicy),抛出异常。根据业务需求,可能需要自定义拒绝策略来处理这种情况。

6、CachedThreadPool 适应场景

CachedThreadPool 适用于以下几种场景:


  1. 大量短生命周期任务CachedThreadPool 适用于执行大量短生命周期的任务,这些任务的执行时间远小于线程创建销毁的时间开销。由于它可以动态地创建和销毁线程,因此非常适合处理这种类型的任务。

  2. 高度并发的任务: 在高并发任务场景中,CachedThreadPool 可以快速响应任务的增加,通过创建新线程来处理任务,提升系统的并发处理能力。

  3. 临时或突发性高并发请求: 当应用面临临时或突发性的高并发请求时,CachedThreadPool 能够根据需要创建新线程来应对这些请求,而不必担心线程池中的线程数量限制。

  4. 资源受限环境: 在资源受限的环境中,CachedThreadPool 可以避免因为线程数量过多而导致的资源耗尽问题。它通过回收空闲线程来减少资源占用。

  5. 异步处理: 对于需要异步处理的任务,CachedThreadPool 可以提供高效的异步处理能力,尤其是在任务数量不确定或频繁变化的情况下。

  6. 任务执行时间不确定: 如果任务的执行时间不确定,或者有些任务执行时间非常短,而有些任务可能需要较长时间,CachedThreadPool 可以灵活地调整线程数量,以适应不同的任务需求。

  7. 避免频繁的线程创建和销毁: 由于 CachedThreadPool 会在线程空闲超过一定时间后销毁线程,因此它可以避免因为频繁创建和销毁线程而带来的性能开销。

发布于: 刚刚阅读数: 6
用户头像

智慧属心窍之锁 2019-05-27 加入

擅长于通信协议、微服务架构、框架设计、消息队列、服务治理、PAAS、SAAS、ACE\ACP、大模型

评论

发布
暂无评论
CachedThreadPool线程池设计/场景案例/性能调优/场景适配(架构篇)_Java_肖哥弹架构_InfoQ写作社区