Java线程池的工作机制详解

 更新时间:2024年12月25日 09:48:39   作者:高锰酸钾_  
本文讲述了Java线程池的工作机制,包括线程池的创建、任务调度、线程复用、资源管理和拒绝策略,通过合理配置线程池参数,可以提升系统的并发性能和稳定性

Java线程池的工作机制

线程池是一种多线程管理机制,用于限制和控制并发线程的数量,以提升系统性能和资源利用率,降低频繁创建和销毁线程的开销,线程池是 Java 并发编程中的重要工具之一,广泛应用于高性能、多线程的场景

线程池通过复用已创建的线程执行多个任务,避免线程的频繁创建和销毁,线程池可以限制线程数量,防止大量线程导致的系统资源耗尽,线程池使用队列管理任务,支持任务调度和优先级,线程池提供策略处理超出能力范围的任务

我们可以使用Java提供的ThreadPoolExecutor类来创建一个线程池实例,让我们先来看一下他的构造方法:

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

可以看到他的构造方法有七个参数

  • corePoolSize:核心线程数,线程池中始终保持的线程数量
  • maximumPoolSize:最大线程数,线程池中允许的最大线程数量
  • keepAliveTime:空闲线程的存活时间,超过该时间的空闲线程将被回收
  • unit:时间单位,是keepAliveTime的单位
  • workQueue:任务队列,用于存储等待执行的任务
  • threadFactory:线程工厂,用于创建新线程
  • handler:拒绝策略,用于处理超出线程池能力范围的任务

那么为什么除了传入一个核心线程数之外,还要传入最大线程数呢?任务队列中又是哪些任务在排队等待呢?我们一起来探讨一下线程池的工作机制

假设创建一个核心线程为2,最大线程数为4的线程池:

ThreadPoolExecutor pool = new ThreadPoolExecutor(
            2,   // 核心线程数量
            4,   // 最大线程数量
            60,  // 空闲线程最大存活时间
            TimeUnit.SECONDS, // 单位
            new ArrayBlockingQueue<>(2), //创建任务队列
            Executors.defaultThreadFactory(),  // 创建线程工厂
            new ThreadPoolExecutor.AbortPolicy() // 任务拒绝策略
);

核心线程

如果同一时刻来了两个任务:任务1任务2,那么自然就会把两个任务交给两个核心线程去执行:

等待队列

如果同一时刻提交了4个新的任务,但是我们定义的线程池只有两个核心线程用来执行任务1任务2,此时核心线程全部繁忙,新任务会被放入等待队列,那么任务3任务4就会进入等待队列中等待,队列有容量限制,我们上面传入的阻塞队列容量是2:

临时线程

如果同一时刻提交的任务非常多,比如提交了6个任务,那么核心线程依旧会执行任务1任务2,由于此时核心线程全部繁忙,新任务会被放入等待队列,任务3任务4会被放如等待队列中等待执行

但是将任务5放入等待队列时,等待队列已满,线程池会尝试创建非核心线程:临时线程来执行新的任务,但是核心线程与临时线程的总和不得超过最大线程数量,也就是我们传入的4,所以此时线程池会创建2个临时线程来执行任务5任务6

临时线程用于处理高峰期任务,但是临时线程并不是核心线程,当临时线程处于空闲状态超过 keepAliveTime 后,临时线程就会被销毁

任务拒绝

如果任务数量超过了线程池最大处理能力(核心线程 + 临时线程 + 等待队列),则执行拒绝策略,例如同一时间提交了7个新任务,按照上面的运行机制,任务1任务2任务5任务6会被线程执行,任务3任务4会在等待队列中等待空闲线程

但是由于核心线程 + 临时线程 + 等待队列全部满员,此时任务7就会执行拒绝策略,共有四种拒绝策略:

任务拒绝策略说明
ThreadPoolExecutor.AbortPolicy默认策略 丢弃任务并抛出RejectedExecutionException异常
ThreadPoolExecutor.DiscardPolicy丢弃任务,但是不抛出异常
ThreadPoolExecutor.DiscardOldestPolicy抛弃等待队列中等待时间最久的任务,把当前任务加入等待队列
ThreadPoolExecutor.CallerRunsPolicy调用任务的run()方法绕过线程池直接执行

这就是线程池的工作机制,线程池通过任务复用和资源管理提升了系统的并发性能,但使用时需结合具体场景合理配置参数,掌握线程池机制并深入理解其应用场景,将有效提升 Java 开发效率和系统稳定性

那么通常在我们的项目中,线程池的容量应该设置为多大呢?

线程容量

项目中的线程容量(即线程池的大小)设置需要基于项目的类型来制定,不同的项目设置不同的容量:

CPU密集型任务

对于主要依赖CPU计算的任务(如数据处理、图像渲染),线程数量建议接近或等于CPU核心数(包括逻辑核心)。

计算公式

这样可以充分利用CPU,但又不会因线程上下文切换过多而导致性能下降。

I/O密集型任务

对于涉及大量I/O操作的任务(如文件读写、网络请求、数据库查询),线程池可以设置为CPU核心数的多倍,因为I/O操作通常会让线程处于阻塞状态。

计算公式

更多线程可以隐藏I/O等待时间,提升系统吞吐量

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Spring事务执行流程及如何创建事务

    Spring事务执行流程及如何创建事务

    这篇文章主要介绍了Spring事务执行流程及如何创建事务,帮助大家更好的理解和学习使用spring框架,感兴趣的朋友可以了解下
    2021-03-03
  • MyBatis中的JdbcType映射使用介绍

    MyBatis中的JdbcType映射使用介绍

    这篇文章主要介绍了MyBatis中的JdbcType映射使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Java基础教程之Map遍历的5种方式

    Java基础教程之Map遍历的5种方式

    Map作为Java中的一种集合,以键值对的形式存放一批数据,经常会被我们应用在项目中,这篇文章主要给大家介绍了关于Java基础教程之Map遍历的5种方式,需要的朋友可以参考下
    2024-01-01
  • Java数据结构中双向链表的实现

    Java数据结构中双向链表的实现

    这篇文章主要介绍了Java数据结构中双向链表的实现,双向链表是一种常见的数据结构,它允许在链表中的任意位置进行高效的插入和删除操作,需要的朋友可以参考下
    2022-05-05
  • SpringBoot使用RestTemplate的示例详解

    SpringBoot使用RestTemplate的示例详解

    RestTemplate继承自InterceptingHttpAccessor并且实现了RestOperations接口,其中RestOperations接口定义了基本的RESTful操作,这些操作在RestTemplate中都得到了实现,这篇文章主要介绍了SpringBoot使用RestTemplate,需要的朋友可以参考下
    2023-05-05
  • Java abstract class 与 interface对比

    Java abstract class 与 interface对比

    这篇文章主要介绍了 Java abstract class 与 interface对比的相关资料,需要的朋友可以参考下
    2016-12-12
  • 详解Spring与Mybatis的整合方法(基于Eclipse的搭建)

    详解Spring与Mybatis的整合方法(基于Eclipse的搭建)

    这篇文章主要介绍了Spring与Mybatis的整合方法(基于Eclipse的搭建),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • springboot与vue实现简单的CURD过程详析

    springboot与vue实现简单的CURD过程详析

    这篇文章主要介绍了springboot与vue实现简单的CURD过程详析,围绕springboot与vue的相关资料展开实现CURD过程的过程介绍,需要的小伙伴可以参考一下
    2022-01-01
  • Java函数式编程(九):Comparator

    Java函数式编程(九):Comparator

    这篇文章主要介绍了Java函数式编程(九):Comparator,本文是系列文章的第9篇,其它文章请参阅本文底部的相关文章,需要的朋友可以参考下
    2014-09-09
  • Java lambda 循环累加求和代码

    Java lambda 循环累加求和代码

    这篇文章主要介绍了Java lambda 循环累加求和代码,具有很的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08

最新评论