Java 线程池介绍与实践

文章目录

  • 引言
  • 概念
  • 优势
  • Java 中的线程池实现
    • 线程池的核心参数
      • 1. corePoolSize:核心线程数
      • 2. maximumPoolSize:最大线程数
      • 3. keepAliveTime:线程空闲时间
      • 4. unit:时间单位
      • 5. workQueue:任务队列
      • 6. threadFactory:线程工厂
      • 7. handler:拒绝策略
  • 创建线程池的方式
    • 1. 固定大小的线程池FixedThreadPool
    • 2. 缓存线程池CachedThreadPool
    • 3. 单线程线程池SingleThreadExecutor
    • 4. 定时线程池ScheduledThreadPool
    • 5. 自定义线程池 ThreadPoolExecutor
    • 强制规定
  • 结论

引言

在现代软件开发中,多线程编程技术被广泛应用于提高应用程序的性能和响应速度。Java 语言提供了丰富的多线程支持,其中线程池是一种非常重要的机制,用于管理和重用线程,从而减少线程创建和销毁带来的开销。本文将详细介绍 Java 中的线程池概念、工作原理以及如何在实际项目中有效使用线程池。

概念

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在线程池中复用已创建的线程。通过这种方式,线程池可以控制运行的线程数量,处理过程中,负责在运行完毕后重新添加线程到线程池中,以供后续新任务使用。

优势

  • 减少创建和销毁线程的开销:线程的创建和销毁都是昂贵的操作,尤其是在频繁创建和销毁线程的情况下。线程池通过复用已存在的线程减少了这种开销。
  • 提高响应速度:当任务到达时,无需等待线程创建即可立即执行。
  • 提高线程的可管理性:线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性。使用线程池可以有效地控制运行的线程数量,合理利用系统资源。
  • 提供更强大的功能:如定时执行、定期执行、线程中断等。

Java 中的线程池实现

Java 提供了 java.util.concurrent 包来支持线程池的创建和管理。其中,ExecutorService 接口是线程池的主要接口,ThreadPoolExecutor 类则是 ExecutorService 的一个实现,提供了更加灵活的线程池配置选项。

线程池的核心参数

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

1. corePoolSize:核心线程数

线程池中保持的最小线程数,即使这些线程处于空闲状态也不会被回收。
通常可以按照任务类型参考如下方式设置核心线程数:

  • CPU密集型任务:选择较小的线程池大小,推荐核心线程数 = CPU核心数 + 1
  • I/O密集型任务:选择较大的线程池大小,因为I/O操作会导致线程阻塞,需要更多的线程来保持CPU的利用率。推荐核心线程数 = CPU核心数 * 2
    实际项目中,可以基于这些参数进行初始化,然后再进行严格测试后确定最终参数。
  1. 如果当前线程数小于corePoolSize,即便其他工作线程是空闲的,也会创建新的线程来处理新提交的任务
  2. 当线程数大于等于corePoolSize且小于maximumPoolSize时,只有当工作队列满了之后才会创建新的线程。
  3. 如果设置了allowCoreThreadTimeOut(true),则核心线程也会在空闲时间超过keepAliveTime后被终止。

2. maximumPoolSize:最大线程数

线程池中允许的最大线程数。

核心线程数和最大线程数都是线程池的重要参数,它们都可以动态设置,但是需要遵循一些规则:

  • 动态设置核心线程数可能会影响线程池的整体性能和稳定性,因此应该谨慎操作。
  • 在已经提交了一些任务的情况下,如果减小核心线程数,可能导致已提交任务无法处理。
  • 最大线程数不能小于核心线程数。
  • 增大最大线程数可能会对系统资源产生压力,应该慎重考虑。
  1. 当线程数已经达到maximumPoolSize且工作队列已满时,线程池会拒绝新任务,此时会触发拒绝策略。
  2. 合理设置maximumPoolSize可以防止系统资源耗尽,特别是在处理大量并发任务时。

3. keepAliveTime:线程空闲时间

线程池中超过corePoolSize的空闲线程等待新任务的最长时间。

  1. 如果线程空闲时间超过了keepAliveTime,则这些线程会被终止,直到线程数等于corePoolSize。
  2. 设置合理的keepAliveTime可以平衡资源利用率和响应速度。

4. unit:时间单位

keepAliveTime 的时间单位。

常见的时间单位包括TimeUnit.SECONDS、TimeUnit.MINUTES、TimeUnit.HOURS等。

5. workQueue:任务队列

用于保存等待执行的任务的阻塞队列。
常见类型

  • LinkedBlockingQueue:基于链表结构的阻塞队列,吞吐量通常要高于ArrayBlockingQueue。
  • ArrayBlockingQueue:基于数组结构的有界阻塞队列,先进先出(FIFO)。
  • SynchronousQueue:不存储元素的阻塞队列,每个插入操作必须等待另一个线程的对应移除操作。
  • PriorityBlockingQueue:具有优先级的无界阻塞队列。

选择合适的任务队列类型对线程池的性能影响很大。
有界队列可以防止资源耗尽,但可能导致任务被拒绝;无界队列可以无限接收任务,但可能占用大量内存。

6. threadFactory:线程工厂

用于创建新线程的工厂。
《阿里巴巴Java开发手册》中有一个强制规定:创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。

  1. 可以通过自定义ThreadFactory来设置线程的名称、优先级等属性。
  2. 默认的ThreadFactory会创建一个默认优先级的线程。

7. handler:拒绝策略

当线程池和任务队列都满时,用于处理新提交任务的策略。

常见策略

  • AbortPolicy:默认策略,抛出RejectExecutionException异常。
  • CallerRunsPolicy:由调用线程(提交任务的线程)执行该任务,不会丢弃任务。
  • DiscardPolicy:直接丢弃任务,不抛出异常。
  • DiscardOldestPolicy:丢弃队列中最老的任务,然后尝试重新提交新任务。
  1. 选择合适的拒绝策略可以避免任务丢失或系统崩溃。
  2. 在生产环境中,通常建议使用CallerRunsPolicy或自定义拒绝策略来处理任务。

创建线程池的方式

1. 固定大小的线程池FixedThreadPool

创建方式:Executors.newFixedThreadPool(int nThreads)

特点

  • 线程池大小固定为nThreads
  • 如果所有线程都在忙,新的任务会被放入队列中等待。
  • 适用于负载较重、处理时间较长的任务。

适用场景:适用于需要控制并发数的应用,比如WEB服务器处理请求。

2. 缓存线程池CachedThreadPool

创建方式:Executors.newCachedThreadPool()

特点

  • 线程池的大小没有限制,可以根据需要创建新的线程
  • 空闲线程等待60s,之后会被回收

适用场景:适用于执行大量耗时短的任务,如I/O操作、网络请求等。

3. 单线程线程池SingleThreadExecutor

创建方式:Executors.newSingleThreadExecutor()

特点

  • 只有一个线程来执行任务,保证所有任务按顺序执行

适用场景:适用于需要保证任务顺序的场景,如日志记录、文件写入等。

4. 定时线程池ScheduledThreadPool

创建方式:Executors.newScheduledThreadPool(int corePoolSize)

特点

  • 支持定时和周期性任务的执行
  • 可以指定延迟执行任务或定期执行任务

适用场景:适用于需要定时执行或周期性执行任务的场景,如定时备份、定时清理等。

5. 自定义线程池 ThreadPoolExecutor

创建方式:直接使用 ThreadPoolExecutor 构造函数

特点

  • 提供了更多的配置选项,如核心线程数、最大线程数、线程空闲时间、任务队列等。
  • 可以根据具体需求进行灵活配置。

适用场景:适用于需要高度定制化线程池的场景,如高性能服务器、复杂业务逻辑等。

强制规定

《阿里巴巴Java开发手册》有一个强制规定:线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
Executors返回的线程池对象的弊端如下:

  • FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
  • CachedThreadPool和ScheduledThreadPool:允许创建的线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。

结论

线程池是 Java 多线程编程中的一个重要组成部分,合理地使用线程池不仅可以提高应用程序的性能,还能增强系统的稳定性和可靠性。开发者应该根据实际应用场景选择合适的线程池类型,并正确配置相关参数,以达到最佳效果。随着多核处理器的普及,掌握线程池的使用技巧对于现代软件开发而言变得越来越重要。

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

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

相关文章

PyAEDT:Ansys Electronics Desktop API 简介

在本文中&#xff0c;我将向您介绍 PyAEDT&#xff0c;这是一个 Python 库&#xff0c;旨在增强您对 Ansys Electronics Desktop 或 AEDT 的体验。PyAEDT 通过直接与 AEDT API 交互来简化脚本编写&#xff0c;从而允许在 Ansys 的电磁、热和机械求解器套件之间无缝集成。通过利…

定时器(QTimer)与随机数生成器(QRandomGenerator)的应用实践——Qt(C++)

一、QTimer与QRandomGenerator &#xff08;一&#xff09;QTimer&#xff08;定时器&#xff09;[2] QTimer类为定时功能提供了一个高级编程接口。在使用QTimer时&#xff0c;实例化一个QTimer对象并将其timeout()发射信号与合适的信号槽相连接。通过调用QTimer的start()函数…

用redis的zset实现日榜,周榜,月榜

思路&#xff1a; 1.初始化一个月的数据&#xff1a; /*** 初始化一个月数据*/Testpublic void initMonthData(){//计算当前时间小时的keylong hourSystem.currentTimeMillis()/(1000*60*60);for(int i1;i<24*30;i){String key"W_hour"(hour-i);Random random new…

通过shell脚本分析部署nginx网络服务

通过shell脚本分析部署nginx网络服务 1.接收用户部署的服务名称 [rootlocalhost xzy]# vim 1.sh [rootlocalhost xzy]# chmod x 1.sh [rootlocalhost xzy]# ./1.sh2.判断服务是否安装 已安装&#xff1b;自定义网站配置路径为/www&#xff1b;并创建共享目录和网页文件&…

威胁驱动的网络安全方法论

摘要 目前的网络安全风险管理实践很大程度上是由合规性要求驱动的&#xff0c;这使得公司/组织不得不在安全控制和漏洞上投入人力/物力。&#xff08;风险管理涉及多个方面&#xff0c;包括资产、威胁、漏洞和控制&#xff0c;并根据事故发生的可能性及造成的影响进行评估。威…

『VUE』30. 生命周期的介绍(详细图文注释)

目录 生命周期生命周期的8阶段生命周期小例子总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 生命周期 每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤&#xff0c;比如设置好数据侦听&#xff0c;编译模板&#xf…

idea 通过git撤销commit但未push的操作

1、undo commit 适用情况&#xff1a;代码修改完了&#xff0c;已经Commit了&#xff0c;但是还未push&#xff0c;然后发现还有地方需要修改不想提交本次记录了。这时可以进行Undo Commit&#xff0c;修改后再重新Commit。注意&#xff1a;如果已经进行了Push&#xff0c;线上…

【graphics】图形绘制 C++

众所周知&#xff0c;周知所众&#xff0c;图形绘制对于竞赛学僧毫无用处&#xff0c;所以这个文章&#xff0c;专门对相关人员教学&#xff08;成长中的码农、高中僧、大学僧&#xff09;。 他人经验教学参考https://blog.csdn.net/qq_46107892/article/details/133386358?o…

Spring Boot出现java: 错误: 无效的源发行版:16的解决方式

第一步&#xff1a; 修改为SDK的目标字节码版本 第二步&#xff1a;CtrlShiftAltS进入项目结构 第三步&#xff1a;pom.xml文件中 在网上搜索和自己SDK适配的Springboot版本&#xff0c;1.8对应的是2.7.1&#xff08;可以用&#xff09; 修改Java版本为1.8 最后的最后&a…

FPGA 第6讲 简单组合逻辑多路选择器

时间&#xff1a;2024.11.11-11.14 一、学习内容 1.组合逻辑 组合逻辑是VerilgHDL设计中一个重要组成部分。从电路本质上讲&#xff0c;组合逻辑电路的特点是输出信号只是当前时刻输入信号的函数&#xff0c;与其他时刻的输入状态无关&#xff0c;无存储电路&#xff0c;也没…

【C++初阶】C++入门

1、C第一个程序 C是脱胎于C语言的&#xff0c;所以也包含了C语言绝大多数的内容&#xff0c;C兼容C语言绝大多数的语法,在C语言中能实现的程序在C中也是可以执行的&#xff0c;但需要将定义文件代码的后缀改为.cpp 就比如hello world程序 // test.cpp #include<stdio.h&g…

selenium元素定位校验以及遇到的元素操作问题记录

页面元素定位方法及校验 使用比较多的是通过id、class和xpath来对元素进行定位。在定位前可以现在浏览器验证是否可以找到指定的元素。这样就不用每添加一个元素定位都运行代码来检查定位方式表达式是否正确。 使用XPATH定位 在浏览器F12&#xff0c;找到元素&#xff0c;在元…

网络安全之国际主流网络安全架构模型

目前&#xff0c;国际主流的网络安全架构模型主要有&#xff1a; ● 信息技术咨询公司Gartner的ASA&#xff08;Adaptive Security Architecture自适应安全架构&#xff09; ● 美国政府资助的非营利研究机构MITRE的ATT&CK&#xff08;Adversarial Tactics Techniques &…

CC工具箱使用指南:【CAD导出界址点Excel】

一、简介 群友定制工具。 面图层导出界址点Excel表之前已经做过好几个&#xff0c;这个工具则是将CAD导出Excel。 CAD数据如下&#xff1a; 工具将如上截图中的边界线导出界址点Excel&#xff0c;并记录下面内的文字。 二、工具参数介绍 点击【定制工具】组里的【CAD导出界…

如何在项目中用elementui实现分页器功能

1.在结构部分复制官网代码&#xff1a; <template> 标签: 这是 Vue 模板的根标签&#xff0c;包含所有的 HTML 元素和 Vue 组件。 <div> 标签: 这是一个普通的 HTML 元素&#xff0c;包裹了 el-pagination 组件。它没有特别的意义&#xff0c;只是为了确保 el-pagi…

Linux安装Nginx和Nginx基础配置

下载Nginx 方式一&#xff1a;通过官网下载后上传 通过官网下载安装包。下载地址https://nginx.org/en/download.html 这里选择稳定版的进行下载。 这里使用FinalShell终端工具操作&#xff0c;使用其他工具操作亦可。FinalShell工具下载地址&#xff1a;http://www.hostbuf…

Ubuntu20.04从零安装IsaacSim/IsaacLab

Ubuntu20.04从零安装IsaacSim/IsaacLab 电脑硬件配置&#xff1a;安装Isaac sim方案一&#xff1a;pip安装方案二&#xff1a;预构建二进制文件安装1、安装ominiverse2、在ominiverse中安装isaac sim&#xff0c;下载最新的4.2版本 安装Isaac Lab1、IsaacLab环境克隆2、创建con…

C++ STL知识点100问

1问&#xff1a;STL有哪几类&#xff0c;对其进行简单描述 答&#xff1a;STL 主要由适配器 allocator&#xff0c;容器 container&#xff0c;算法 algorithm,迭代器 iterator 和仿函数 functor5大类构成。 适配器allocator&#xff1a;STL 提供了三个容器适配器&#xff1a;…

基于Java Springboot宠物猫售卖管理系统

一、作品包含 源码数据库全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据库&#xff1a;…

python处理单元格语句去重

Python处理单元格内连续出现的重复词语 1. 环境配置 导入必要的库 import pandas as pd # 数据处理库 import re # 正则表达式库 import jieba # 中文分词库2. 处理字符串 检查输入有效性‌ &#xff1a;如果输入是 NaN、None 或非字符串类型&#xff0c;则直接返回输入。…