Java编程基本功大揭秘 | 详解深入分析Java线程池源码和底层原理,掌握实战技巧【1】

详解深入分析Java线程池源码和底层原理

  • 文章大纲
  • 引言
    • Java线程池概念及重要性
  • `ThreadPoolExecutor`类的概述
    • `ThreadPoolExecutor`类的基本功能和作用
      • **基本功能**
      • **核心作用**
    • `ThreadPoolExecutor`主要构造函数及其参数
      • 继承关系链
      • 功能介绍
      • ThreadPoolExecutor 构造器
        • 构造器参数
          • 构造器中各个参数的含义
            • corePoolSize
            • maximumPoolSize
            • keepAliveTime
            • unit
            • workQueue
            • threadFactory
            • handler
      • 接口继承关系链
  • 总结与展望

文章大纲

在这里插入图片描述

引言

早期的编程实践中,直接使用新线程执行任务虽直观且易实现,但在高并发场景下却面临性能瓶颈。当系统需处理大量短暂并发任务时,频繁创建和销毁线程会导致巨大的开销,降低系统性能,甚至可能因资源过度消耗导致系统崩溃。为解决线程频繁创建和销毁的问题,我们需要高效复用线程的机制。

Java线程池概念及重要性

Java的线程池(Thread Pool)提供了这样的解决方案:预先创建并管理线程组,任务执行时从池中获取线程,任务完成后线程返回池中等待新任务。这种方式显著减少线程创建和销毁,大幅提升系统并发处理能力。


ThreadPoolExecutor类的概述

Java中的ThreadPoolExecutor是线程池的核心实现,提供灵活的配置和管理方法。要深入理解其工作原理和使用,可从关键方法入手,逐步探索其实现逻辑。

ThreadPoolExecutor类的基本功能和作用

在Java中,ThreadPoolExecutor是线程池框架的核心组件,它允许开发者以高度可配置和灵活的方式管理线程资源。其核心功能是为应用程序提供一个线程池,从而优化和控制线程的使用,特别是在处理大量并发任务时。

基本功能

  1. 线程管理与复用ThreadPoolExecutor管理一个线程池,当任务提交给线程池时,线程池会尝试复用已有的线程来执行任务,而不是为每个新任务都创建一个新线程。这大大减少了线程创建和销毁的开销。
  2. 任务队列:当线程池中的线程都在忙碌时,新提交的任务会被放置在一个任务队列中等待执行。ThreadPoolExecutor允许你配置这个队列的大小和类型,以适应不同的应用场景。
  3. 线程生命周期管理ThreadPoolExecutor允许你配置线程的生命周期,包括核心线程数、最大线程数、线程空闲时间等。当线程空闲超过指定时间后,多余的线程会被销毁以节省资源。
  4. 任务拒绝策略:当任务队列已满且所有线程都在忙碌时,新提交的任务将被拒绝。ThreadPoolExecutor提供了几种内置的任务拒绝策略,同时也允许你自定义拒绝策略。

核心作用

  1. 提高性能:通过复用线程,ThreadPoolExecutor显著减少了线程创建和销毁的开销,从而提高了应用程序的性能。
  2. 资源管理ThreadPoolExecutor允许你精细控制线程资源的使用,包括线程的数量、任务的排队策略等,从而更有效地管理系统的资源。
  3. 简化并发编程:使用ThreadPoolExecutor,开发者可以更加专注于业务逻辑的实现,而无需过多关注线程的管理和调度。
  4. 提供灵活的扩展性:通过调整线程池的配置参数,ThreadPoolExecutor可以适应不同规模和需求的应用程序,提供了很好的扩展性。

ThreadPoolExecutor主要构造函数及其参数

继承关系链

在这里插入图片描述

ThreadPoolExecutor 实现了 ExecutorService 接口, ExecutorService 扩展了 Executor 接口。

功能介绍

  • Executor:这是Java中执行已提交任务的对象的接口,提供了一种将任务与任务执行机制(通常是线程)解耦的方式。

  • ExecutorService:这是一个扩展了Executor接口的接口,它提供了更全面的生命周期管理(例如关闭、终止)和任务提交机制(例如execute, submit等)。ExecutorService通常用于控制和管理线程,它内部封装了一组线程,使得线程的使用更加简便和安全。

  • AbstractExecutorService:实际上,Java标准库中没有名为AbstractExecutorService的接口。可能您是想引用一个抽象类,但ExecutorService接口本身通常被具体类(如ThreadPoolExecutor)实现,而不是由抽象类来扩展。在标准库中,有一个AbstractExecutorService类的可能性很低,但如果有这样的类,它可能提供了一些ExecutorService接口的默认实现。

  • ThreadPoolExecutor:这是一个实现了ExecutorService接口的具体类,它提供了线程池的实现,允许用户配置核心线程数、最大线程数、线程空闲时间、任务队列等参数。ThreadPoolExecutor是线程池框架中最常用的实现之一,它高效地管理线程资源的复用,降低了系统的开销。

ThreadPoolExecutor 构造器

java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类,因此如果要透彻地了解Java中的线程池,必须先了解这个类。下面我们来看一下ThreadPoolExecutor类的具体实现源码。

public class ThreadPoolExecutor extends AbstractExecutorService {

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
	BlockingQueue<Runnable> workQueue);

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

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

从上面的代码可以得知,ThreadPoolExecutor继承了AbstractExecutorService类,并提供了四个构造器,事实上,通过观察每个构造器的源码具体实现,发现前面三个构造器都是调用的第四个构造器进行的初始化工作。

构造器参数

了解如何配置线程池。这包括设置核心线程数、最大线程数、队列容量等参数。这些参数的选择将直接影响线程池的性能和稳定性。通过合理地配置这些参数,我们可以在保证系统性能的同时,也避免了资源的过度消耗。

构造器中各个参数的含义

在这里插入图片描述

corePoolSize

corePoolSize 是线程池中的一个关键参数,它决定了线程池中的核心线程数量。

在创建线程池后,初始状态下线程池内部并不包含任何线程。线程池会等待任务的到来,并根据需要创建线程来执行任务。除非显式地调用 prestartAllCoreThreads()prestartCoreThread() 方法,线程池才会预先创建核心线程。从这两个方法的名字就可以推断出,它们的目的是在未接收到任务之前就创建指定数量的线程。

在默认情况下,当第一个任务到达时,线程池会创建一个新线程来执行它。随着更多任务的到达,线程池中的线程数量会逐渐增加,直到达到 corePoolSize 所设定的数量。一旦线程池中的线程数量达到这个核心值,后续到达的任务将不再触发新线程的创建。

此时,如果还有新任务到来,线程池会将它们放入一个缓存队列中等待执行。这个队列通常是一个阻塞队列,用于存储待执行的任务。只有当队列满了,或者线程池中的线程数量低于 maximumPoolSize(最大线程池大小)时,线程池才会考虑创建额外的线程来执行任务。

注意:合理配置 corePoolSize,可以平衡线程创建和销毁的开销与任务执行的效率。如果 corePoolSize 设置得太小,可能会导致大量任务在队列中等待,从而增加任务的延迟;如果设置得太大,又可能浪费系统资源,因为不是所有线程都会同时处于忙碌状态。因此,在实际应用中,需要根据任务的特性和系统资源来合理设置这个参数。

maximumPoolSize

线程池中的maximumPoolSize参数指的是线程池能够容纳的最大线程数量。当线程池中的线程数量达到这个值时,新的任务提交到线程池时,线程池将不会再创建新的线程来处理这些任务,而是根据线程池的其他策略(如队列策略)来决定如何处理这些新任务。

keepAliveTime

线程没有任务执行时最多保持多久时间会终止。

默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。

注意:如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

unit

unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
在这里插入图片描述

workQueue

一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:
在这里插入图片描述
线程池中的阻塞队列(BlockingQueue)是线程池的一个重要组成部分,用于存储待执行的任务。当线程池中的线程数量达到corePoolSize时,新提交的任务会被放入这个队列中等待执行。阻塞队列的类型会影响线程池的行为和性能。以下是您提到的几种阻塞队列的作用和特性:

  • ArrayBlockingQueue(数组类型队列)

    • 特点:基于数组结构的有界阻塞队列。
    • 容量限制:在创建时需要指定队列的容量,一旦队列满了,新提交的任务会被拒绝。
    • 性能:由于是基于数组,它在入队和出队操作上的时间复杂度是O(1),具有较好的性能。
    • 使用场景:适用于有固定大小的任务缓存场景,当任务量比较大时,能够避免在内存中创建大量的对象。
  • LinkedBlockingQueue(链表类型队列)

    • 特点:基于链表结构的有界(但默认大小为Integer.MAX_VALUE,可视为无界)阻塞队列。
    • 容量限制:可以指定队列的容量,但如果不指定,则默认为Integer的最大值,几乎可以认为是无界的。
    • 性能:入队和出队操作的时间复杂度为O(1),但由于是链表结构,实际性能可能会略低于ArrayBlockingQueue。
    • 使用场景:适用于任务量较大,但不想或不需要限制队列大小的场景。
  • SynchronousQueue(同步单元素队列)

    • 特点:一个不存储元素的阻塞队列,也就是说它的容量为1。
    • 容量限制:只能存储一个元素,如果队列中有元素,则新提交的任务可以直接获取执行,否则需要等待其他线程执行完任务后,腾出空间才能继续。
    • 性能:入队和出队操作的时间复杂度接近O(1),但由于其特殊的特性,线程间的交互更为频繁,可能导致更高的线程调度开销。
    • 使用场景:适用于线程池中的线程数量与任务数量大致相等,且任务执行时间较短的场景。
  • PriorityBlockingQueue(具有优先级的队列)

    • 特点:一个支持优先级排序的无界阻塞队列。
    • 容量限制:默认是无界的,可以存储任意数量的任务。
    • 优先级:队列中的元素按照它们的自然排序或者通过提供的Comparator进行排序,优先级高的任务将优先被执行。
    • 性能:由于需要排序,入队和出队操作的时间复杂度可能会高于O(1)。
    • 使用场景:适用于需要按照优先级执行任务的场景,例如,某些重要或紧急的任务需要优先得到处理。

ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。

threadFactory

线程工厂,主要用来创建线程的工厂实现类

public interface ThreadFactory {

    /**
     * Constructs a new {@code Thread}.  Implementations may also initialize
     * priority, name, daemon status, {@code ThreadGroup}, etc.
     *
     * @param r a runnable to be executed by new thread instance
     * @return constructed thread, or {@code null} if the request to
     *         create a thread is rejected
     */
    Thread newThread(Runnable r);
}
handler

表示当拒绝处理任务时的策略,有以下四种取值:
在这里插入图片描述

接口继承关系链

总结与展望

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/754212.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SysML与MBSE的关系

SysML与MBSE的关系 对于任何基于模型的系统工程 &#xff08;MBSE&#xff09; 方法&#xff0c;推荐的最佳实践是基于模型的语言、基于模型的工具、基于模型的流程和基于模型的架构框架的协同应用&#xff0c;如下图所示 系统架构四元组 图。经过十年将SysML应用于棘手的系统…

MATLAB算法实战应用案例精讲-【数模应用】线性判别分析(附MATLAB、python和R语言代码实现)

目录 前言 算法原理 什么是判别分析 线性判别分析(LDA) 数学模型 二分类 多分类LDA ​编辑 算法思想: 费歇(FISHER)判别思想 贝叶斯(BAYES)判别思想 LDA算法流程 LDA与PCA对比 SPSSPRO 1、作用 2、输入输出描述 3、案例示例 4、案例数据 5、案例操作 …

MySQL高级-SQL优化- update 优化(尽量根据主键/索引字段进行数据更新,避免行锁升级为表锁)

文章目录 0、update 优化1、创建表2、默认是行锁3、行锁升级为表锁4、给name字段建立索引 0、update 优化 InnoDB的行锁是针对索引加的锁&#xff0c;不是针对记录加的锁&#xff0c;并且该索引不能失效&#xff0c;否则会从行锁升级为表锁。 1、创建表 create table course(…

【Python机器学习实战】 | 基于支持向量机(Support Vector Machine, SVM)进行分类和回归任务分析

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

物联网 IoT 收录

物联网IoT日常知识收录 thingsboard, nodered是国际大品牌&#xff0c; iotgateway是国内的&#xff0c; 几个scada, pyscada, json-scada都还不错&#xff0c;比较一下。thingsboard-gateway是python系的&#xff0c;如果你愿意&#xff0c;可以用这个作为公司的物联网网关。…

圈子系统搭建教程,以及圈子系统的功能特点,圈子系统,允许二开,免费源码,APP小程序H5

圈子是一款社区与群组的交友工具。你可以在软件内创造一个兴趣的群组从而达到按圈子来交友的效果用户可以根据自己的兴趣爱好。 1. 创建圈子 轻松创建专属圈子&#xff0c;支持付费型社群。 2. 加入圈子 加入不同圈子&#xff0c;设置不同名片&#xff0c;保护隐私。 3. 定…

【笔记】echarts图表的缩放和鼠标滚动冲突的处理解决方案

解决方案不是很好&#xff0c;来源于github的issue&#xff0c;官方提供了&#xff0c;组合键触发缩放的功能。 https://github.com/apache/echarts/issues/5769 https://echarts.apache.org/zh/option.html#dataZoom-inside.zoomOnMouseWheel dataZoom-inside.zoomOnMouseWhe…

java基于ssm+jsp 多人命题系统

1管理员功能模块 管理员登录&#xff0c;管理员通过输入用户、密码等信息进行系统登录&#xff0c;如图1所示。 图1管理员登录界面图 管理员对个人中心进行操作填写原密码、新密码、确认密码并进行添加、删除、修改以及查看&#xff0c;如图2所示。 图2个人信息功能界面图 学…

鸿蒙UI开发快速入门 —— part12: 渲染控制

如果你对鸿蒙开发感兴趣&#xff0c;加入Harmony自习室吧~&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; 扫描下面的二维码关注公众号。 1、前言 在声明式描述语句中开发者除了使用系统组件外&#xff0c;还可…

次世代霍尔电磁摇杆搭配磁悬浮马达,这款手柄手感超丝滑,谷粒金刚3Pro体验

燥热的天气里&#xff0c;周末在家打上几局游戏&#xff0c;确实更容易放松身心&#xff0c;玩游戏的时候&#xff0c;键鼠、手柄一类的游戏外设特别重要&#xff0c;对我们的游戏体验影响很大&#xff0c;所以挑选起来总是格外挑剔。现在国产的游戏手柄已经今非昔比了&#xf…

中国航天:星舰与猛禽发动机数据分析

文章目录 MainReference Main 马斯克坚信&#xff0c;随着星舰的全面投入运营&#xff0c;SpaceX将能够承担地球上主轨道超过99%的载荷质量。这款第三代星舰的起飞推力将跃升至10000吨以上&#xff0c;其有效载荷质量亦将高达200吨以上。 不仅如此&#xff0c;每次发射的成本控…

怎么加快音频播放速度?加快音频播放器的四种方法介绍

怎么加快音频播放速度&#xff1f;许多音乐爱好者对各种类型的歌曲充满了热情&#xff0c;这些歌曲节奏轻快或者缓慢不一&#xff0c;但通常默认的播放速度都是一倍速。有时候&#xff0c;一些旋律悠扬的曲子可能听起来有些慢&#xff0c;这时候一些朋友可能想要尝试加快节奏&a…

树莓派4B学习笔记14:Python多线程编程_线程间的同步通信_(锁‘threading.Lock’)

今日继续学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 版本是4.5.1&#xff1a; 今日学习树莓派与Python的多进程编程_线程间同步通信 文…

Total Uninstall安装及卸载软件

Total Uninstall 的独特之处在于通过其安装的软件可以完整监控到新增或更改的注册表、文件、服务&#xff0c;可一键卸载。但常规的“360软件管家”无法做到以上内容。 借助该机制可用来无限刷新软件试用许可。 1.Total Uninstall 安装第三方软件 点击图中的“安装”&#xf…

NAND闪存原厂铠侠加速推上市,预计10月完成IPO

NAND闪存原厂铠侠Kioxia拟趁着半导体市场回暖及企业财务状况显著提升的契机&#xff0c;加速推进其上市进程。 据报道&#xff0c;公司计划最快于8月底提交IPO申请&#xff0c;目标是在2024年10月末于东京证券交易所完成首次公开募股。此番上市动作不仅反映出市场复苏迹象&…

Postman 怎么测接口?实用教程

在当前&#xff0c;API&#xff08;应用程序接口&#xff09;的使用变得越来越普遍。其中&#xff0c;HTTP/HTTPS API 是最常见的一种。无论是开发前端还是后端&#xff0c;测试 API 都是一个关键环节。Postman 是一种流行且强大的 API 测试工具&#xff0c;能够帮助开发人员轻…

P1114 “非常男女”计划最优解

原题地址 P1114 “非常男女”计划 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 代码题解 AC代码&#xff08;1&#xff09; 因为用的是级的算法&#xff0c;所以最后一个 了&#xff0c;这里使用特判来得到的&#xff0c;给你们放一下代码&#xff1a; #include <bi…

【2024最新版】图解Mysql数据库配置、命令行及Workbench访问(Windows版本)

目录 1. 准备工作1.1 安装MySQL1.2 验证MySQL的环境变量 2. 环境变量配置3. 访问MySQL3.1 命令行访问MySQL3.2 Workbench访问MySQL 1. 准备工作 1.1 安装MySQL 如果您已经安装了MySQL&#xff0c;请从【2. Mysql 环境配置】开始&#xff1b;如果您没有安装MySQL&#xff0c;请…

06 Shell编程实战——案例1

脚本编程步骤&#xff1a; 脚本编程一般分为4个步骤&#xff0c;即先确定需求&#xff0c;然后再确定你所要用到的语句&#xff0c; 需求分析&#xff1a;根据系统管理的需求&#xff0c;分析脚本要实现的功能、功能实现的层次、实现的命令与语句等&#xff1b;命令测试&…

[Cloud Networking] VLAN

1 为什么需要 VLAN(Virtual Local Area Network) VLAN是一个逻辑网络&#xff0c;VLAN将设备/用户进行逻辑分组&#xff0c;VLAN需要在Switch上创建。为什么需要这样呢&#xff1f;为何不能所有设备都在同一个网络&#xff1f; 如下网络&#xff0c;如果设备过多&#xff0c;…