Java线程池详解

目录

前言

线程池概述

线程池的实现

线程池的构造

拒绝策略

任务队列

线程池的工作原理

线程池的监控

Executors线程池工厂

自定义线程池

使用线程池的好处

应用场景

总结


本文详细探讨了线程池在并发编程领域的应用,介绍了ThreadPoolExecutor的核心组件、工作原理,线程池的构造、拒绝策略、任务队列、线程池的监控、线程池工厂等相关内容,并讨论了线程池对系统性能和线程管理的优势。

前言

在面对并发任务处理的场景时,采用多线程策略来并行执行各异的任务成为了提升系统整体执行效率与响应能力的常见手段,然而线程作为操作系统的重要资源,频繁地创建线程不仅会消耗更多的资源,导致频繁的线程上下文切换,加剧共享资源的竞争程度,降低程序的响应速度,还有系统资源耗尽的风险。因此需要对线程的使用进行合理的管理,于是便有了线程池。

线程池概述

线程池的核心功能就是线程的复用,在线程池内,通常会创建一定数量可复用的线程,而不是为每个新任务都单独创建新线程。还有一个阻塞队列,用于保存暂时无法处理的任务,起到缓冲的作用。除此之外,线程池还能定义拒绝策略,当请求的任务太多时,根据拒绝策略抛弃任务,保证已加入线程池的任务可以正常执行完成。这种设计能够显著提高系统资源的使用效率、保证系统的稳定性。

线程池的实现

Java提供了一套Executor框架,帮助开发人员有效地进行线程控制,其本质就是一个线程池,它的核心成员如图所示:

线程池的构造

public ThreadPoolExecutor(int corePoolSizeint maximumPoolSizeLong keepAliveTimeTimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

Java 主要是通过ThreadPoolExecutor类来创建线程池的。

  • corePoolSize:线程池中的核心线程数量。

  • maximumPoolSize:最大线程数,线程池允许创建的最大线程数。

  • keepAliveTime:超出corePoolSize后创建的线程存活时间或者是所有线程最大存活时间,取决于配置。

  • unit:keepAliveTime 的时间单位。

  • workQueue:任务队列,是一个阻塞队列,当线程数达到核心线程数后,会将任务存储在阻塞队列中。

  • threadFactory :线程池内部创建线程所用的工厂,一般用默认即可。

  • handler:拒绝策略,当队列已满并且线程数量达到最大线程数时,会调用该方法处理任务。

拒绝策略

当线程池无法再接收任务时就会根据拒绝策略丢弃任务,JDK自带的拒绝策略实现有4种:

  • AbortPolicy:丢弃任务,抛出运行时异常,这是默认的拒绝策略。

  • CallerRunsPolicy:由提交任务的线程来执行任务。

  • DiscardPolicy:丢弃这个任务,但是不抛异常。

  • DiscardOldestPolicy:从队列中剔除最先进入队列的任务,然后再次提交任务。

如果这些策略无法满足你的需求,你也可以自己实现RejectedExecutionHandler接口自定义拒绝策略,比如快熟返回失败,或者在数据库中记录失败的任务,又或者将任务存在数据库或者缓存中,等到线程池空闲时在取出来执行。

任务队列

  • 直接提交的队列:该功能由SynchronousQueue实现。SynchronousQueue是一个特殊的BlockingQueue,它没有容量,提交的任务不会被保存,而总是将新任务提交给线程执行,如果没有空闲的进程,则尝试创建新的进程,如果进程数量已经达到最大值,则执行拒绝策略。

  • 有界的任务队列:有界的任务队列可以使用ArrayBlockingQueue类实现。可以设置暂存的最大任务数量。

  • 无界的任务队列:无界任务队列一般通过LinkedBlockingQueue类实现。使用无界任务队列当系统的线程数达到corePoolSize后,线程数量就会保持不变。新的任务会加入任务队列。与有界队列相比,除非系统资源耗尽,否则无界的任务队列不存在任务入队失败的情况。

  • 优先任务队列:优先任务队列是带有执行优先级的队列。它通过PriorityBlockingQueue类实现,可以控制任务的执行先后顺序。

线程池的工作原理

  • 线程池创建:在程序启动时或者首次需要时,预先创建一定数量的线程,并将这些线程放入线程池中,等待任务分配。

  • 任务提交:当有新的任务到来时,不是直接创建新线程去执行任务,而是将任务添加到任务队列中。

  • 任务调度与执行:线程池中的空闲线程会从任务队列中取出任务并执行。如果所有线程都在忙碌状态且任务队列已满,根据策略可能拒绝新任务,或者挂起直到有线程可用。

  • 线程复用:任务执行完毕后,线程不会立即销毁,而是返回线程池等待下一次任务分配,这大大减少了创建和销毁线程的开销。

  • 动态调整:线程池可以根据预设的策略动态调整线程数量,比如在任务量激增时增加线程数以应对高负载,或在任务较少时减少线程数以节省资源。

如图所示为线程池的核心执行流程。当任务被提交至线程池时,首先会尝试创建核心线程以执行这些任务。一旦核心线程数量达到预设的最大值,后续任务将会被转入阻塞队列进行排队等待。在阻塞队列达到其容量上限之后,线程池将继而创建非核心线程来进一步处理任务,直至线程总数触及最大限定值。在此之后,根据所配置的拒绝策略,超出承载能力的任务将被适当处理,例如直接丢弃。值得一提的是,线程池允许用户自定义任务拒绝策略,以实现更为灵活的错误处理机制。一种进阶策略可能是将无法立即执行的任务暂存于数据库或缓存系统中,这样一来,即使任务最初被线程池拒绝,依然能够通过检索数据库或缓存来恢复这些任务并考虑后续的重试或其他补偿处理措施。

线程池的监控

对线程池的监控可以帮助我们了解任务的执行状况,方便出问题的时候快速定位,线程池提供了一些方法来获取线程池的运行状态。

  • getCompletedTaskCount():获取已经执行完成的任务数量

  • getLargestPoolSize():获取线程池里曾经创建过的最大的线程数量。

  • getActiveCount():获取正在执行任务的线程数据。

  • getPoolSize():获取当前线程池中线程数量的大小。

  • getTaskCount():返回线程池已接收但尚未完成(包括正在执行和排队等待)的任务总数。

线程池内置的方法也许并不能满足实际需求,可以自己继承ThreadPoolExecutor重写相关方法实现自定义的监控策略,也可以通过引入一些第三方组件来支持更加强大的功能。

Executors线程池工厂

Executors是一个线程池工厂类,提供了创建不同类型线程池的方法,使得创建线程池变得十分简单方便。

  • newFixedThreadPool创建一个线程数量固定的线程池,它的线程数量保持固定,即使没有作业也不会关闭线程。内部使用了一个无界队列LinkedBlockingQueue作为阻塞队列。

  • newCachedThreadPool创建一个缓冲线程池,它的等待队列不缓存任务,当有任务提交时使用空闲线程执行,如果没有空闲线程则创建新线程执行,空闲线程超过60秒没被执行则会被关闭。所以它适合短周期任务,长周期任务可能会创建过多的线程。

  • newSingleThreadExecutor这个线程池只有一个线程,这个线程池可以在线程死后重新启动一个线程来替代原来的线程继续执行下去。

  • newScheduledThreadPool带定时调度功能的线程池。

经常看到一些文章指出不推荐使用Executors创建线程池,因为这些线程池都没有任务的数量或者是线程的数量,可能会导致系统资源耗尽。我个人的看法是,在复杂的场景中确实不推荐使用,但是在简单的、执行过程可预知的一些任务场景中还是没问题的,因为它简洁方便,代码可读性好,能让我早点下班。

自定义线程池

通过 Executors 这个工具类来创建的线程池如果无法满足实际的使用场景,那么在实际的项目中,该如何合理地构造线程池呢?其中线程数的设置主要取决于业务 IO 密集型还是 CPU 密集型。除线程数的设置外,其它的参数设置也需要根据实际需求进行判断。

  • CPU 密集型:指的是任务主要使用来进行大量的计算,没有什么导致线程阻塞,这种场景设置太多的线程,导致线程频繁的上下文切换,反而会降地程序执行的速度,一般线程数设置为CPU核心数。

  • IO 密集型:当执行任务需要大量的io,比如磁盘io,网络io,可能会存在大量的阻塞,阻塞的过程中线程可以执行其它的任务,所以在IO密集型任务中使用多线程可以大大地加速任务的处理。一般线程数设置为2*CPU核心数。

使用线程池的好处

  • 降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

  • 提高响应速度:当任务到达时,可以不需要等到线程创建就能立即执行,提高了响应速度。

  • 线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

  • 程序的健壮性:线程若意外挂掉,线程池会重新创建新线程继续执行,某个任务异常不会影响其它任务执行。

应用场景

线程池技术的应用范围十分广泛,如Web服务器请求处理、数据库连接管理、异步任务执行、定时任务调度、并发性能测试及批量数据处理等诸多领域。它在面对那些具有短期性、高吞吐量以及突发性特点的任务处理需求时,展现了尤为显著的优势。通过预创建和管理线程资源,线程池能有效提升系统对高并发场景的响应速度与处理能力,同时优化资源利用效率,确保系统的稳定性和可靠性。

总结

不同的编程语言提供了不同级别的线程池实现框架,如Java中的ExecutorService接口及其实现类ThreadPoolExecutor。开发者可以根据具体需求配置线程池的核心参数,如核心线程数、最大线程数、任务队列大小、饱和策略等,以达到最佳的性能和资源利用率。总之,线程池作为一种高效管理线程资源的方式,在现代软件开发中扮演着至关重要的角色,特别是在构建高性能、高并发系统时。正确理解和应用线程池,对于提升系统的稳定性和效率具有重要意义。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL的登录、访问、退出

一、登录&#xff1a; 访问MySQL服务器对应的命令&#xff1a;mysql.exe ,位置&#xff1a;C:\Program Files\MySQL\MySQL Server 8.0\bin &#xff08;mysql.exe需要带参数执行&#xff0c;所以直接在图形界面下执行该命令会自动结束&#xff09; 执行mysql.exe命令的时候出…

2024年9月26日历史上的今天大事件早读

1620年9月26日 大明皇帝朱常洛驾崩 1815年9月26日 俄、普、奥三国在巴黎发表缔结“神圣同盟” 1841年9月26日 清代思想家、诗人龚自珍逝世 1849年9月26日 “生理学之父”巴甫洛夫诞生 1909年9月26日 云南陆军讲武堂创办 1953年9月26日 画家徐悲鸿逝世 1980年9月26日 国际…

VulnHub-Narak靶机笔记

Narak靶机笔记 概述 Narak是一台Vulnhub的靶机&#xff0c;其中有简单的tftp和webdav的利用&#xff0c;以及motd文件的一些知识 靶机地址&#xff1a; https://pan.baidu.com/s/1PbPrGJQHxsvGYrAN1k1New?pwda7kv 提取码: a7kv 当然你也可以去Vulnhub官网下载 一、nmap扫…

ChatGPT高级语音助手正式上线!OpenAI:50多种语言、9种声线可选

①OpenAI终于要面向其所有付费用户开放ChatGPT的类人高级人工智能&#xff08;AI&#xff09;语音助手功能——“高级语音模式”&#xff08;AVM&#xff09;&#xff1b; ②所有付费订阅ChatGPT Plus和Team计划的用户&#xff0c;都将可以使用新的AVM功能&#xff0c;不过该模…

Tomcat后台弱口令部署war包

1.环境搭建 cd /vulhub/tomcat/tomcat8 docker-compose up -d 一键启动容器 2.访问靶场 点击Manager App tomcat8的默认用户名和密码都是tomcat进行登录 3.制作war包 先写一个js的一句话木马 然后压缩成zip压缩包 最后修改后缀名为war 4.在网站后台上传war文件 上传war文件…

功能测试详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、测试项目启动与研读需求文档 &#xff08;一&#xff09; 组建测试团队 1、测试团队中的角色 2、测试团队的基本责任 尽早地发现软件程序、系统或产品中所…

Keil提示main.c(2): warning C318: can‘t open file ‘LCD1602.h‘

应该是创建项目的时候没有手敲.h文件&#xff0c;直接点击下面图片里面红框里面的选项&#xff0c;导致编译的时候keil没有.h文件的目录&#xff0c;所以报错&#xff0c;手动添加.h文件的目录即可。 解决方法&#xff1a; 1.找到该位置。 2.添加路径。&#xff08;路径为自己…

3d gaussian splatting公式推导

1. 离散公式推导 nerf中连续的积分渲染公式是&#xff1a; 其中被遮挡率&#xff1a; 那么转换为离散公式后有&#xff1a; 其中&#xff0c;代表j时刻的时间差&#xff0c;将其带入渲染公式&#xff1a; 设透明度 则被遮挡率 有 而gaussian-splating的公式与ner…

速卖通欧盟资质认证怎么弄?速卖通GPSR超全认证攻略请收下!

8月19日&#xff0c;速卖通官方发布了关于欧盟《通用产品安全法规》&#xff08;简称&#xff1a;GPSR&#xff09;的管控通知。 通知显示&#xff1a;针对未按照法规要求完成合规的商品&#xff0c;平台已于9月中旬开始陆续执行屏蔽管控&#xff0c;预计在12月1日前完成&…

尚硅谷MyBatis笔记

Mybatis简介 MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下&#xff0c;iBatis3.x正式更名为MyBatis。代码于2013年11月迁移到GithubiBatis一词来源于“intern…

Windows下VS进行OPenCV源码编译 调试 注意事项教程(建议收藏)

为了更深入的学习和了解OPenCV的开源魅力&#xff0c;我们可以将OPenCV的源码进行编译&#xff0c;重新生成解决方案&#xff0c;得到二进制文件&#xff0c;或者修改原版官方的OpenCV代码&#xff0c;并编译后为自己所用&#xff0c;也可以编译后进入到源码中调试&#xff0c;…

【代码随想录训练营第42期 Day61打卡 - 图论Part11 - Floyd 算法与A * 算法

目录 一、Floyd算法与A * 算法 1、Floyd算法 思想 伪代码 2、 A * 算法 思想 伪代码 二、经典题目 题目一&#xff1a;卡码网 97. 小明逛公园 题目链接 题解&#xff1a;Floyd 算法 题目二&#xff1a;卡码网 127. 骑士的攻击 题目链接 题解&#xff1a;A * 算法&a…

啤酒:从饮品到文化的演变

在人类饮品的长河中&#xff0c;啤酒以其不同的魅力走过了一段漫长的历史旅程。它不仅仅是一种简单的饮品&#xff0c;更是一种文化的象征&#xff0c;一种生活的态度。今天&#xff0c;我们将一起追溯啤酒从单一的饮品到丰富文化的演变过程&#xff0c;并感受Fendi Club精酿啤…

LeetCode讲解篇之238. 除自身以外数组的乘积

文章目录 题目描述题解思路题解代码 题目描述 题解思路 对于该题&#xff0c;我们可以先使用一个循环记录所有非零元素的乘积结果和非零元素的个数 如果非零元素个数为0&#xff0c;则非零元素的乘积除以数组对应位置的数字就是除自身以外的数组的乘积如果非零元素个数为1&am…

达梦数据库配置SSL通信加密

相关概念&#xff1a; SSL通过在发送方和接收方之间建立加密通道&#xff0c;确保数据在传输过程中的安全性和完整性。 SSL的关键特点 加密通信&#xff1a;SSL使用对称和非对称加密技术来加密数据&#xff0c;确保数据在传输过程中不被窃听或篡改。 身份验证&#xff1a;通…

centos7 更新 yum源 为 阿里云 LTS

centos7 更新 yum源 为 阿里云 按照下面的 步骤 1,2&#xff0c;3,4 来一遍 参考文档 CentOS yum源设置为国内aliyun yum源 https://developer.aliyun.com/article/1523301?spm5176.26934562.main.2.16c938e4ys9prQ CentOS 镜像 https://developer.aliyun.com/mirror/cent…

理解C语言之深入理解指针(三)

目录 1. 字符指针变量 2. 数组指针变量 2.1 数组指针变量是什么&#xff1f; 2.2 数组指针变量怎么初始化 3. ⼆维数组传参的本质 4. 函数指针变量 4.1 函数指针变量的创建 4.2 函数指针变量的使⽤ 4.3 两段有趣的代码 4.3.1 typedef 关键字 5. 函数指针数组 6. 转移…

构建高可用和高防御力的云服务架构第五部分:PolarDB(5/5)

引言 云计算与数据库服务 云计算作为一种革命性的技术&#xff0c;已经深刻改变了信息技术行业的面貌。它通过提供按需分配的计算资源&#xff0c;使得数据存储、处理和分析变得更加灵活和高效。在云计算的众多服务中&#xff0c;数据库服务扮演着核心角色。数据库服务不仅负…

PHP之 实现https ssl证书到期提醒,通过企微发送消息

参考文章 https://blog.51cto.com/17099933344/1935194 https://blog.csdn.net/m0_37346206/article/details/127333463 https://www.cnblogs.com/tk-bolg/p/18108106 使用的企微接口 https://qyapi.weixin.qq.com/cgi-bin/message/send 查询 ssl证书到期时间 // ssl证书即将…

Linux·进程概念(上)

1.操作系统 任何计算机系统都包含一个基本的程序合集&#xff0c;称为操作系统(Operator System)。笼统的理解&#xff0c;操作系统包括&#xff1a; 内核(进程管理&#xff0c;内存管理&#xff0c;文件管理&#xff0c;驱动管理) 其他程序(函数库&#xff0c;shell程序) OS的…