Java 线程池之 ThreadPoolExecutor

        Java线程池,特别是ThreadPoolExecutor,是构建高性能、可扩展应用程序的基石之一。它不仅关乎效率,还直接关系到资源管理与系统稳定性。想象一下,如果每来一个请求就创建一个新的线程,服务器怕是很快就要举白旗了。而ThreadPoolExecutor就是那个懂得“量入为出”,合理调配资源的智慧管家。

详细介绍

        ThreadPoolExecutor是Java并发编程中线程池的核心实现类,它位于java.util.concurrent包下,由Doug Lea设计,是Java 1.5引入的重要特性之一。ThreadPoolExecutor提供了一种灵活的方式来管理和控制线程的创建、执行、调度和回收,以高效地执行大量异步任务。

  ThreadPoolExecutor实现了ExecutorService接口,提供了强大的线程池管理功能。它的构造方法允许高度定制,主要包括核心线程数、最大线程数、线程空闲时间、任务队列、拒绝策略等关键参数。

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
  • corePoolSize:线程池的基本大小,即使没有任务执行,也会保持这么多线程。
  • maximumPoolSize:线程池最大线程数,当队列满且工作线程数小于最大值时,会创建新线程执行任务。
  • keepAliveTime:非核心线程闲置时的超时时长,超过这个时间会被回收。
  • unitkeepAliveTime的时间单位。
  • workQueue:用于保存待处理任务的阻塞队列,有多种队列类型可以选择,如ArrayBlockingQueueLinkedBlockingQueueSynchronousQueue等。
  • threadFactory:线程工厂,用来创建新线程。
  • handler:拒绝策略处理器,当线程池和队列都满时,如何处理新提交的任务。

使用场景

  • 高并发请求处理:如Web服务器处理大量HTTP请求。
  • 批量数据处理:如图像处理、文件操作等大量IO操作。
  • 定时任务执行:结合ScheduledThreadPoolExecutor实现定时任务。
  • 并行计算:科学计算、大数据处理等需要并行处理的场景。

Java代码示例

import java.util.concurrent.*;public class ThreadPoolDemo {public static void main(String[] args) {// 创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(5, // 核心线程数10, // 最大线程数1, // 空闲线程存活时间,单位秒TimeUnit.SECONDS,new LinkedBlockingQueue<>(20), // 任务队列Executors.defaultThreadFactory(), // 线程工厂new ThreadPoolExecutor.AbortPolicy() // 拒绝策略,超出时抛出异常);// 提交任务for (int i = 0; i < 30; i++) {int taskId = i;executor.execute(() -> downloadTask(taskId));}// 关闭线程池executor.shutdown();while (!executor.isTerminated()) {// 等待所有任务完成}System.out.println("所有下载任务已完成!");}private static void downloadTask(int taskId) {System.out.println("开始下载任务 " + taskId);try {Thread.sleep(1000); // 模拟下载耗时} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("任务 " + taskId + " 下载完成!");}
}

实际开发中的使用和注意事项

  1. 合理配置线程池参数:根据任务类型和系统资源合理设置线程池大小、队列长度等。
  2. 避免任务无限提交:确保任务提交策略不会导致内存溢出。
  3. 资源回收:使用完毕后调用shutdown()shutdownNow(),确保线程池和资源正确释放。
  4. 监控线程池状态:定期检查线程池状态,如使用getPoolSize()getActiveCount()等方法。
  5. 异常处理:实现或自定义RejectedExecutionHandler来妥善处理拒绝的任务。

优缺点

优点

  • 提高性能:减少线程创建和销毁的开销。
  • 资源管理:有效控制线程数量,避免资源耗尽。
  • 灵活性:通过自定义参数满足不同场景需求。

缺点

  • 配置复杂:需要对业务和系统有深入理解才能合理配置。
  • 调试难度:线程池内部错误和异常处理相对复杂。
  • 滥用风险:不恰当使用可能导致性能下降或资源耗尽。

可能遇到的问题及解决方案

1. 任务积压

问题描述:当线程池中线程已达到最大数,且任务队列也已满载时,新提交的任务将面临被拒绝的风险,导致任务积压在应用层面,可能引起内存溢出或响应延迟。

解决方案

  • 调整队列大小:适当增加队列容量,但这会增加内存占用,且只是临时解决方案。
  • 动态调整最大线程数:根据系统负载动态调整maximumPoolSize,使用如ThreadPoolExecutor.CallerRunsPolicy拒绝策略让调用者线程直接执行任务,减轻队列压力。
  • 使用有界队列:如ArrayBlockingQueue,确保队列不会无限增长,迫使线程池拒绝超出队列容量的任务。
  • 监控与报警:建立线程池和任务队列的监控机制,当接近阈值时触发报警,以便及时调整策略或扩容。

2. 线程泄漏

问题描述:如果任务执行过程中抛出了未捕获的异常,或者finally块中的资源清理代码未能正确执行,可能导致线程无法正确回收,进而造成线程池“泄漏”。

解决方案

  • 确保异常处理:在RunnableCallable的任务实现中,使用try-catch-finally结构,确保异常被捕获且资源得到正确释放。
  • 自定义异常处理器:实现或定制Thread.UncaughtExceptionHandler,捕获并处理未捕获的异常,必要时记录日志并尝试恢复。
  • 使用守护线程:确保ThreadPoolExecutor的线程是守护线程(通过ThreadFactory设置),这样当主线程结束时,即使有线程未正确终止,JVM也会退出。

3. 拒绝策略处理不当

问题描述:当线程池和任务队列都达到饱和状态时,预设的拒绝策略(如默认的AbortPolicy)会直接抛出RejectedExecutionException,如果不做特殊处理,可能导致任务丢失。

解决方案

  • 选择合适的拒绝策略:根据业务需求选择或自定义拒绝策略,如CallerRunsPolicy让调用者线程执行任务,DiscardPolicy丢弃任务不抛出异常,或DiscardOldestPolicy丢弃最旧的任务来接纳新任务。
  • 二次提交或重试机制:捕获RejectedExecutionException后,可以根据情况设计任务的重试逻辑,或者将任务放入备用队列稍后重试。
  • 动态扩容:在检测到拒绝策略触发时,考虑是否可以动态增加线程池的容量,但需谨慎,避免无限制增长。

4. 死锁

问题描述:在多线程环境下,如果任务间存在不当的同步或等待关系,可能导致死锁,即两个或多个线程互相等待对方释放资源,无法继续执行。

解决方案

  • 避免嵌套锁:尽量减少锁的使用,避免在持有锁的同时去获取另一个锁。
  • 按照相同的顺序获取锁:如果必须使用多个锁,确保所有线程按照相同的顺序获取锁。
  • 超时机制:在尝试获取锁时使用带有超时的尝试锁定方法,如tryLock(long time, TimeUnit unit),避免无限等待。
  • 检测与诊断:使用Java的jstack命令或集成监控工具定期检查死锁情况,一旦发现,通过日志分析或人工介入解决。

        通过深入理解和恰当应用ThreadPoolExecutor,我们不仅能提升应用的性能,还能确保系统的稳定性和可维护性。合理使用和维护ThreadPoolExecutor是保证Java应用并发性能的关键。面对问题,采取恰当的预防和应对措施至关重要,当然持续的监控与调优也是必不可少的环节。通过这些方法,可以有效提升应用的稳定性和效率。

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

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

相关文章

【图书推荐】《图神经网络基础、模型与应用实战》

本书目的 详解PyTorch 图神经网络基础理论、模型与十多个应用案例&#xff0c;带领读者掌握图神经网络在自然语言处理、计算机视觉、推荐系统、社交网络4个领域的应用开发方法&#xff0c;丰富读者利用深度学习算法解决实际问题的能力。 本书案例 图卷积网络实现图注意力网络…

Comate,一款基于文心大模型的智能编程助手

一、官网 Baidu Comate官网 二、安装VSCode 如何下载安装VSCode 三、VSCode安装Comate 安装方式1 访问Comate官网点击 立即安装Comate插件 按钮快速安装 安装方式2 访问VSCode市场中的BaiduComate 点击 Install 按钮访问扩展详情界面 2.打开VSCode 3.安装Comate 四、…

先经营好自己,才是成事最坚实的基础!做事要稳!

电影《教父》里有句著名的台词说&#xff1a;花半秒钟就能看透事物本质的人&#xff0c;和花一辈子也看不透事物本质的人&#xff0c;注定是截然不同的命运。而这所谓的“看透本质”&#xff0c;就是事物的底层逻辑。 底层逻辑是一种解决问题的思维模式。底层逻辑越坚固&#x…

中金:如何把握不断轮动的资产“风口”

从比特币到日股&#xff0c;到黄金与铜再到当前的港股&#xff0c;每次超预期大涨后都透支回调。 今年以来资产的“风口”不断轮动&#xff0c;从比特币到日股&#xff0c;到黄金与铜&#xff0c;再到当前的港股&#xff0c;资产仿佛“接力”般交替领先&#xff0c;同时“风口”…

js api part6

正则表达式 正则表达式 &#xff08;Regular Expression&#xff09;是用于 匹配字符串中字符组合 的模式。在 JavaScript中&#xff0c;正则表达式也是对象。通常用来查找、替换那些符合正则表达式的文本&#xff0c;许多语言都支持正则表达式。 正则表达式在 JavaScript中的…

spring框架学习记录(3)

Spring事务 Spring事务简介 事务作用&#xff1a;在数据层保障一系列的数据库操作同成功同失败Spring事务作用&#xff1a;在数据层或业务层保障一系列的数据库操作同成功或同失败 Spring事务角色 事务管理员&#xff1a;发起事务方&#xff0c;在Spring中通常指代业务层开…

AI智能分析视频监控行业的发展趋势和市场发展浅析

监控视频AI智能分析技术的现状呈现出蓬勃发展的态势&#xff0c;这一技术源于计算机视觉和人工智能的研究&#xff0c;旨在将图像与事件描述之间建立映射关系&#xff0c;使计算机能够从视频图像中分辨出目标信息。 在技术上&#xff0c;监控视频AI智能分析技术已经实现了对视…

Ps中 饱和度 和 自然饱和度 的区别?

1.饱和度&#xff08;Saturation&#xff09;&#xff1a;在Photoshop中&#xff0c;饱和度是一个全局性调整&#xff0c;它影响图像中所有颜色的鲜艳程度。当你增加饱和度时&#xff0c;所有的颜色都会变得更浓烈、更鲜艳&#xff1b;相反&#xff0c;减小饱和度会使图像整体变…

小猪APP分发:重塑应用分发市场的创新力量

在移动互联网蓬勃发展的今天&#xff0c;应用分发平台作为连接开发者与用户的桥梁&#xff0c;扮演着至关重要的角色。然而&#xff0c;随着市场的饱和&#xff0c;如何在众多平台中脱颖而出&#xff0c;为开发者提供更宽广的舞台&#xff0c;同时确保用户能够便捷、安全地获取…

程序员必备的7大神器,效率飞起!

我们都知道程序员在工作时&#xff0c;会经常遇到任务繁重的情况&#xff0c;为了提高效率&#xff0c;程序员们也会借助一些软件&#xff0c;那么哪些软件可以帮助程序员们提高工作效率呢&#xff1f; 整理不易&#xff0c;关注一波&#xff01;&#xff01; 1. Xftp 7 Xft…

06-beanFactoryPostProcessor的执行

文章目录 invokeBeanFactoryPostProcessors(beanFactory)invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);invokeBeanFactoryPostProcessors(regularPostProc…

将ESP工作为AP路由模式并当成服务器

将ESP8266模块通过usb转串口接入电脑 ATCWMODE3 //1.配置成双模ATCIPMUX1 //2.使能多链接ATCIPSERVER1 //3.建立TCPServerATCIPSEND0,4 //4.发送4个字节在链接0通道上 >ATCIPCLOSE0 //5.断开连接通过wifi找到安信可的wifi信号并连接 连接后查看自己的ip地址变为192.168.4.…

Java中next()与nextLine()的区别[不废话,直接讲例子]

在使用牛客进行刷题时&#xff0c;我们很多时候会遇到这样的情况&#xff1a; 区别很简单&#xff0c;如果你要输入用空格或者回车分开的数据如&#xff1a; abc_def_ghi 这三组数据&#xff08; _ 是空格&#xff09; 用hasNext: 执行结果&#xff1a; 如果只用换行符号进行…

6层板学习笔记1

说明:笔记基于6层全志H3消费电子0.65MM间距BGA 目的:掌握各类接口的布局思路和布线,掌握DDR高速存储设计 1、网表的导入是原理图的元件电气连接关系,位号,封装,名称等参数信息的总和 2、原理图文件包含(历史版本记录,功能总框图,电源树,GPIO分配,DDR功能,CPU,US…

Mysql:Before start of result set

解决方法&#xff1a;使用resultSet.getString&#xff08;&#xff09;之前一定要调用resultSet.next() ResultSet resultSet statement1.executeQuery();while (resultSet.next()){String username1 resultSet.getString("username");int id1 resultSet.getInt…

pytorch基础: torch.unbind()

1. torch.unbind 作用 说明&#xff1a;移除指定维后&#xff0c;返回一个元组&#xff0c;包含了沿着指定维切片后的各个切片。 参数&#xff1a; tensor(Tensor) – 输入张量dim(int) – 删除的维度 2. 案例 案例1 x torch.rand(1,80,3,360,360)y x.unbind(dim2)print(&…

案例分享:BACnet转Modbus提升暖通系统互操作性

现代智能建筑中系统的集成与互操作性是决定其智能化程度的关键因素。随着技术的发展&#xff0c;不同标准下的设备共存成为常态&#xff0c;而BACnet与Modbus作为楼宇自动化领域广泛采用的通讯协议&#xff0c;它们之间的无缝对接显得尤为重要。本文将通过一个实际案例&#xf…

全面的Partisia Blockchain 生态 4 月市场进展解读

Partisia Blockchain 是一个以高迸发、隐私、高度可互操作性、可拓展为特性的 Layer1 网络。通过将 MPC 技术方案引入到区块链系统中&#xff0c;以零知识证明&#xff08;ZK&#xff09;技术和多方计算&#xff08;MPC&#xff09;为基础&#xff0c;共同保障在不影响网络完整…

如何在matlab时间序列中X轴标注月-日

一般我们使用的时间序列都是以年为单位&#xff0c;比如下图&#xff1a; 而如果要绘制月尺度的时间变化图&#xff0c;则需要调整X轴的标注。下面代码展示了如何绘制小时尺度的降水数据。 [sname2,lon2,lat2] kml2xy(GZ_.kml); nc_bound2 [lon2,lat2]; area_ind2inpolygon(e…

WSL介绍(Windows10内置的Linux子系统)

最近发现在Windows10下不用安装虚拟机也可以使用Linux&#xff0c;然后发现原来2016年就已经有这个功能了&#xff0c;下面来介绍下如何使用。 首先我的win10版本信息如下&#xff0c;以免部分版本不支持&#xff0c;可以做个参考。 需要进到控制面板里将Linux子系统功能打开&a…