当前位置: 首页 > news >正文

线程池(ThreadPool):使用ExecutorService、ThreadPoolExecutor等线程池管理并发任务以及底层实现原理

线程池(ThreadPool)是一种通过预先创建和维护一组线程的机制,用来高效管理并发任务。线程池不仅能减少创建和销毁线程的开销,还能更好地控制并发任务的执行。Java 中提供了多种方式来管理线程池,其中包括 ExecutorServiceThreadPoolExecutor 等关键类。

一、线程池的基本概念

线程池的核心思想是维护一组可复用的线程来执行任务,而不是为每个任务创建新线程。这样可以避免频繁的线程创建和销毁,提升系统性能。线程池的主要好处包括:

  1. 减少资源消耗:通过复用线程,避免了频繁创建和销毁线程的成本。
  2. 提升响应速度:任务不需要等待新线程的创建,因为线程池中已经有线程可用。
  3. 控制并发数:线程池可以通过限制线程的数量,控制系统中并发任务的数量,防止资源耗尽。
  4. 任务管理:线程池提供了任务队列,可以管理提交的任务,支持任务的调度和优先级。

Java 的 Executor 框架为开发者提供了一种标准化的方式来使用线程池,它将任务的提交与任务的执行分离,使得开发者无需关心底层线程的管理细节。

二、ExecutorService 和 ThreadPoolExecutor 的使用

ExecutorServicejava.util.concurrent 包中的一个接口,提供了一组用于管理线程池的抽象方法。ThreadPoolExecutorExecutorService 接口的一个实现类,提供了线程池的核心功能。

1. 使用 ExecutorService

ExecutorService 是线程池的上层接口,可以通过静态方法 Executors 创建常用的线程池。以下是几种常用的线程池类型:

  • 固定线程池(FixedThreadPool):创建一个固定大小的线程池,线程池中始终有指定数量的线程在运行。新任务提交后,如果线程池中所有线程都在执行任务,则新任务会进入任务队列等待。

    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
    
  • 缓存线程池(CachedThreadPool):创建一个缓存线程池。线程池的大小不固定,随着需求动态增长。线程闲置时会被回收,适合执行大量短期任务。

    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    
  • 单线程池(SingleThreadExecutor):创建一个只有单个线程的线程池,所有任务将在同一个线程中顺序执行。

    ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
    
  • 调度线程池(ScheduledThreadPool):用于定时或周期性执行任务。

    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
    
2. 提交任务

任务可以通过 ExecutorService 提交执行,通常有以下几种方法:

  • execute(Runnable):提交一个 Runnable 任务,执行没有返回结果。

    fixedThreadPool.execute(() -> {System.out.println("Task executed by thread pool");
    });
    
  • submit(Runnable)submit(Callable):提交任务并返回 Future 对象,Future 可用于获取任务执行结果。

    Future<String> future = fixedThreadPool.submit(() -> {return "Task result";
    });
    
3. 关闭线程池

使用完线程池后,应该关闭它以释放资源。可以调用以下方法关闭线程池:

  • shutdown():会等待线程池中的任务执行完毕后再关闭。

    fixedThreadPool.shutdown();
    
  • shutdownNow():立即停止所有任务,并尝试中断正在执行的线程。

    fixedThreadPool.shutdownNow();
    

三、ThreadPoolExecutor 的底层实现原理

ThreadPoolExecutor 是 Java 线程池的核心实现类,它提供了高度可配置的线程池管理机制。我们可以通过构造方法自定义线程池的核心参数,如线程数、队列类型、拒绝策略等。其构造方法如下:

public ThreadPoolExecutor(int corePoolSize,        // 核心线程数int maximumPoolSize,     // 最大线程数long keepAliveTime,      // 非核心线程的存活时间TimeUnit unit,           // 存活时间的单位BlockingQueue<Runnable> workQueue, // 任务队列ThreadFactory threadFactory,       // 线程工厂,用于创建新线程RejectedExecutionHandler handler   // 拒绝策略
)
1. 核心参数介绍
  • corePoolSize:核心线程数,当提交任务时,如果当前线程数小于核心线程数,即使线程池中有空闲线程,也会创建新的线程来执行任务。

  • maximumPoolSize:线程池的最大线程数,当任务队列已满且线程数小于最大线程数时,线程池会创建新线程来执行任务。

  • keepAliveTime:非核心线程的空闲时间超过此时间后将被终止(如果当前线程数大于 corePoolSize)。

  • workQueue:任务队列,用于存放等待执行的任务。常用的任务队列类型有:

    • ArrayBlockingQueue:有界队列,任务达到队列上限时,新的任务将被阻塞或拒绝。
    • LinkedBlockingQueue:无界队列,适合任务量较大的场景。
    • SynchronousQueue:没有容量的队列,提交的任务必须直接交给线程执行,否则会创建新线程。
  • RejectedExecutionHandler:当线程池和任务队列都满时,新的任务将被拒绝。可以选择不同的拒绝策略:

    • AbortPolicy:默认策略,直接抛出 RejectedExecutionException 异常。
    • CallerRunsPolicy:调用执行任务的线程(通常是提交任务的线程)来执行任务。
    • DiscardPolicy:直接丢弃任务,不抛异常。
    • DiscardOldestPolicy:丢弃队列中最旧的任务,然后重新尝试执行当前任务。
2. 工作流程

ThreadPoolExecutor 的工作流程大致可以分为以下几个步骤:

  1. 任务提交:当任务通过 execute()submit() 方法提交时,线程池首先会检查当前线程数是否少于 corePoolSize,如果是,则创建新的线程执行任务。

  2. 任务入队:如果线程数已经达到 corePoolSize,任务会被放入 workQueue 队列中等待执行。

  3. 创建新线程:当队列已满且线程数未达到 maximumPoolSize,线程池会创建新的线程来执行任务。

  4. 拒绝策略:如果线程数已经达到 maximumPoolSize 且队列已满,线程池会根据 RejectedExecutionHandler 策略拒绝新提交的任务。

  5. 任务执行:线程从任务队列中取出任务并执行,任务执行完毕后,线程不会立即销毁,而是保持存活状态,等待下一个任务。如果线程的空闲时间超过 keepAliveTime,并且当前线程数超过 corePoolSize,该线程将被终止。

  6. 线程销毁:当线程池中的所有线程都处于空闲状态且线程数大于 corePoolSize 时,线程池会根据 keepAliveTime 逐步销毁多余的线程,直到只剩下核心线程。

3. 任务队列与线程数的关系

ThreadPoolExecutor 的任务处理策略基于任务队列和线程数的配置,可以分为以下几种情况:

  • 如果当前线程数小于 corePoolSize,则即使队列不满,线程池也会优先创建新线程。
  • 如果队列已满且线程数小于 maximumPoolSize,线程池会继续创建新线程来执行任务。
  • 如果队列已满且线程数已达到 maximumPoolSize,任务将被拒绝,触发拒绝策略。

四、总结

Java 中的 ExecutorServiceThreadPoolExecutor 提供了一种标准化、可扩展的线程池管理机制,可以高效管理并发任务。通过线程池,开发者能够减少线程频繁创建和销毁带来的开销,控制并发数,提升系统性能。

线程池的底层实现主要基于核心线程数、最大线程数、任务队列、存活时间以及拒绝策略等参数的组合。通过合理配置线程池,可以在不同场景下实现性能优化和资源控制。

相关文章:

线程池(ThreadPool):使用ExecutorService、ThreadPoolExecutor等线程池管理并发任务以及底层实现原理

线程池&#xff08;ThreadPool&#xff09;是一种通过预先创建和维护一组线程的机制&#xff0c;用来高效管理并发任务。线程池不仅能减少创建和销毁线程的开销&#xff0c;还能更好地控制并发任务的执行。Java 中提供了多种方式来管理线程池&#xff0c;其中包括 ExecutorServ…...

人力资源数据集分析(二)_随机森林与逻辑回归

数据入口&#xff1a;人力资源分析数据集 - Heywhale.com 数据说明 字段说明EmpID唯一的员工IDAge年龄AgeGroup年龄组Attrition是否离职BusinessTravel出差&#xff1a;很少、频繁、不出差DailyRate日薪Department任职部门&#xff1a;研发部门、销售部门、人力资源部门Dista…...

【30天玩转python】数据库操作

数据库操作 数据库是应用程序中用于存储和管理数据的核心组件。Python 提供了多种与数据库交互的方式&#xff0c;支持不同类型的数据库&#xff0c;包括关系型数据库&#xff08;如 MySQL、PostgreSQL&#xff09;和 NoSQL 数据库&#xff08;如 MongoDB&#xff09;。在这篇…...

PTT:Point Tree Transformer for Point Cloud Registration 论文解读

目录 一、导言 二、相关工作 1、基于Transformer的点云配准 2、针对点云的局部注意力 三、PTT 1、KPconv提取特征 2、Tree Transformer Encoder 3、Decoder 4、估计姿态 5、损失函数 四、实验 1、对比不同Backbone 2、运行时间对比 3、对比不同PTT方法下RR指标的…...

C++速通LeetCode中等第7题-和为K的子数组(巧用前缀和)

巧用哈希表与前缀和&#xff0c;前缀和差为k的两个序号之间的数组就是满足条件的子数组&#xff0c;用哈希表来存放每个序号的前缀和。 前缀和就是头元素到当前序号子数组元素的和 class Solution { public:int subarraySum(vector<int>& nums, int k) {unordered_…...

【读书笔记-《30天自制操作系统》-23】Day24

本篇内容依然比较简单&#xff0c;主要是优化窗口功能以及开发定时器应用程序。首先是优化窗口的切换功能&#xff0c;实现通过键盘和鼠标切换窗口&#xff0c;然后是实现通过鼠标关闭窗口。接着实现不同窗口输入状态的切换&#xff0c;最后是实现定时器的API与应用程序。 1.…...

XML:DOM4j解析XML

XML简介&#xff1a; 什么是XML&#xff1a;XML 是独立于软件和硬件的信息传输工具。 XML 的设计宗旨是传输数据&#xff0c;而不是显示数据。XML 标签没有被预定义。您需要自行定义标签。XML不会做任何事情&#xff0c;XML被设计用来结构化、存储以及传输信息。 XML可以发明…...

15.5 创建监控控制平面的service

本节重点介绍 : k8s中service的作用和类型创建k8s控制平面的service 给prometheus采集用&#xff0c; 类型clusterIp kube-schedulerkube-controller-managerkube-etcd service的作用 Kubernetes Service定义了这样一种抽象&#xff1a; Service是一种可以访问 Pod逻辑分组…...

【Docker Nexus3】maven 私库

1.部署环境 window 11 x64Docker Desktop 4.34.1 (166053) Docker Engine v27.2.0 1.1.Docker 镜像源 1.1.1.Docker Engine 配置 {"builder": {"features": {"buildkit": true},"gc": {"defaultKeepStorage": "32…...

Docker本地部署Chatbot Ollama搭建AI聊天机器人并实现远程交互

文章目录 前言1. 拉取相关的Docker镜像2. 运行Ollama 镜像3. 运行Chatbot Ollama镜像4. 本地访问5. 群晖安装Cpolar6. 配置公网地址7. 公网访问8. 固定公网地址 前言 本文主要分享如何在群晖NAS本地部署并运行一个基于大语言模型Llama 2的个人本地聊天机器人并结合内网穿透工具…...

MySQL:用户管理

添加用户 create user usernamelocalhost identified by user_password;删除用户 drop user usernamelocalhost;查看所有用户 输入格式 select user,host from mysql.user; 输出 mysql> select user,host from mysql.user; ----------------------------- | user …...

论文《Mixture of Weak Strong Experts on Graphs》笔记

【Mowst 2024 ICLR】论文提出了一种新的图神经网络架构&#xff0c;称为Mixture of weak and strong experts&#xff08;Mowst&#xff09;&#xff0c;通过将轻量级的多层感知机&#xff08;MLP&#xff09;作为弱专家和现成的GNN作为强专家相结合&#xff0c;以处理图中的节…...

【诉讼流程-健身房-违约-私教课-诉讼书提交流程-民事诉讼-自我学习-铺平通往法律的阶梯-讲解(3)】

【诉讼流程-健身房-违约-私教课-诉讼书提交流程-民事诉讼-自我学习-铺平通往法律的阶梯-讲解&#xff08;3&#xff09;】 1、前言说明2、流程说明3、现场提交&#xff08;线下&#xff09;4、网上提交1-起诉书样例2-起诉书编写&#xff08;1&#xff09;原告信息&#xff1a;&…...

数据结构(Day14)

一、学习内容 结构体 概念 引入&#xff1a;定义整数赋值为10 int a10; 定义小数赋值为3.14 float b3.14; 定义5个整数并赋值 int arr[5] {1 , 2 , 3 , 4 ,5}; 定义一个学生并赋值学号姓名成绩 定义一个雪糕并赋值名称产地单价 问题&#xff1a;没有学生、雪糕 数据类型 解决&…...

Paragon NTFS for Mac和Tuxera NTFS for Mac,那么两种工具有什么区别呢?

我们在使用Mac系统读取U盘的过程中往往会遇到一个问题&#xff0c;那就是U盘插进电脑无法显示&#xff0c;或者只能读取不能编辑。出现这种情况的原因就一般是格式错误。 很多小伙伴在解决这种问题的时候会选择使用U盘读写工具&#xff0c;那么哪一种读写工具比较好呢&#xf…...

HashTable结构体数组实现

写了个哈希表&#xff0c;底层逻辑基于结构体数组&#xff0c;核心结构:HashNode,结构外壳:HashTable_R,冲突处理以后会加的(QwQ)~ 目前代码&#xff1a; #ifndef PYIC_X #define PYIC_Xunsigned int PYIC_Hash(unsigned int Val, unsigned int Mov) {unsigned int Ht[4] { …...

Python 管理 AWS ElastiCache 告警

在 AWS 环境中,监控和管理 ElastiCache 集群的性能是至关重要的。本文将介绍如何使用 Python 和 AWS SDK (boto3) 来自动创建和删除 ElastiCache 集群的 CloudWatch 告警。我们将分两部分来讨论:创建告警和删除告警。 第一部分:创建 ElastiCache 告警 首先,让我们看看如何…...

【无人机设计与控制】四旋翼无人机俯仰姿态保持模糊PID控制(带说明报告)

摘要 为了克服常规PID控制方法在无人机俯仰姿态控制中的不足&#xff0c;本研究设计了一种基于模糊自适应PID控制的控制律。通过引入模糊控制器&#xff0c;实现了对输入输出论域的优化选择&#xff0c;同时解决了模糊规则数量与控制精度之间的矛盾。仿真结果表明&#xff0c;…...

[数据集][目标检测]不同颜色的安全帽检测数据集VOC+YOLO格式7574张5类别

重要说明&#xff1a;数据集里面有2/3是增强数据集&#xff0c;请仔细查看图片预览&#xff0c;确认符合要求在下载&#xff0c;分辨率均为640x640 数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件…...

确保 App 跟踪透明度权限:Flutter 中的实践

确保 App 跟踪透明度权限&#xff1a;Flutter 中的实践 在数字广告领域&#xff0c;用户隐私保护已成为一个重要议题。随着 iOS 14 的发布&#xff0c;Apple 引入了 App Tracking Transparency (ATT) 框架&#xff0c;要求开发者在跟踪用户行为以提供个性化广告之前必须获得用…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...