为什么要用线程池?
线程池是一种管理和复用线程资源的机制,它由一个线程池管理器和一组工作线程组成。线程池管理器负责创建和销毁线程池,以及管理线程池中的工作线程。工作线程则负责执行具体的任务。
线程池的主要作用是管理和复用线程资源,避免了线程的频繁创建和销毁所带来的开销。
线程池包含两个重要的组成部分:
-
线程池大小:指线程池中所能容纳的最大线程数。线程池大小一般根据系统的负载情况和硬件资源来设置。
-
工作队列:用于存放等待执行的任务。当线程池中的工作线程已经全部被占用时,新的任务将被加入到工作队列中等待执行。
线程池创建方式
Java中线程池的创建方式主要有以下几种:
-
使用 ThreadPoolExecutor 类手动创建:通过 ThreadPoolExecutor 类的构造函数自定义线程池的参数,包括核心线程数、最大线程数、线程存活时间、任务队列等。
-
使用 Executors 类提供的工厂方法创建:通过 Executors 类提供的一些静态工厂方法创建线程池,例如 newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool 等。
-
使用 Spring 框架提供的 ThreadPoolTaskExecutor 类:在 Spring 框架中可以通过 ThreadPoolTaskExecutor 类来创建线程池。
不同的创建方式适用于不同的场景,通常可以根据实际情况选择合适的方式创建线程池。手动创建 ThreadPoolExecutor 类可以灵活地配置线程池参数,但需要对线程池的各项参数有一定的了解;使用 Executors 工厂方法可以快速创建线程池,但可能无法满足特定的需求,且容易出现内存溢出的情况;而 Spring 框架提供的 ThreadPoolTaskExecutor 类则只能在 Spring 框架中使用。
线程池使用
ThreadPoolExecutor 使用
ThreadPoolExecutor 线程的创建与使用示例如下:
import java.util.concurrent.*;public class ThreadPoolDemo {public static void main(String[] args) {// 创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(2, // 核心线程数5, // 最大线程数60, // 线程池中线程的空闲时间(单位为秒)TimeUnit.SECONDS, // 时间单位new ArrayBlockingQueue<>(10) // 任务队列);// 提交任务for (int i = 1; i <= 20; i++) {final int taskId = i;executor.submit(() -> {System.out.println("执行任务:" + taskId + ",线程名称:" + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟任务执行时间} catch (InterruptedException e) {e.printStackTrace();}});}// 关闭线程池executor.shutdown();}
}
在上面的示例中,我们通过 ThreadPoolExecutor 类手动创建了一个线程池,设置了线程池的核心线程数为 2,最大线程数为 5,线程空闲时间为 60 秒,任务队列为长度为 10 的 ArrayBlockingQueue。然后我们通过 submit() 方法向线程池中提交了 20 个任务,每个任务会在执行时输出自己的编号和执行线程的名称,然后睡眠1秒钟模拟任务执行时间。最后,我们调用 shutdown() 方法关闭线程池。
Executors 使用
import java.util.concurrent.*;public class ExecutorsDemo {public static void main(String[] args) {// 创建线程池ExecutorService executor = Executors.newFixedThreadPool(5);// 提交任务for (int i = 1; i <= 10; i++) {final int taskId = i;executor.submit(() -> {System.out.println("执行任务:" + taskId + ",线程名称:" + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟任务执行时间} catch (InterruptedException e) {e.printStackTrace();}});}// 关闭线程池executor.shutdown();}
}
在上面的示例中,我们使用了 Executors 工厂类中的 newFixedThreadPool() 方法创建了一个线程池,该线程池有 5 个固定线程。然后我们通过 submit() 方法向线程池中提交了 10 个任务,每个任务会在执行时输出自己的编号和执行线程的名称,然后睡眠 1 秒钟模拟任务执行时间。最后,我们调用 shutdown() 方法关闭线程池。值得注意的是,使用 Executors 工厂类创建线程池虽然非常简单,但是在实际生产环境中并不推荐,因为这种方式很容易导致线程资源被耗尽,从而影响系统的性能和稳定性。
ThreadPoolTaskExecutor 使用
Spring 中 ThreadPoolTaskExecutor 的使用示例如下:
import java.util.concurrent.*;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;public class ThreadPoolTaskExecutorDemo {public static void main(String[] args) {// 创建线程池ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(2); // 核心线程数executor.setMaxPoolSize(5); // 最大线程数executor.setQueueCapacity(10); // 任务队列长度executor.initialize();// 提交任务for (int i = 1; i <= 20; i++) {final int taskId = i;executor.submit(() -> {System.out.println("执行任务:" + taskId + ",线程名称:" + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟任务执行时间} catch (InterruptedException e) {e.printStackTrace();}});}// 关闭线程池executor.shutdown();}
}
在上面的示例中,我们使用了 Spring 框架中的 ThreadPoolTaskExecutor 类创建了一个线程池,设置了线程池的核心线程数为 2,最大线程数为 5,任务队列长度为 10。然后我们通过 submit() 方法向线程池中提交了 20 个任务,每个任务会在执行时输出自己的编号和执行线程的名称,然后睡眠1秒钟模拟任务执行时间。最后,我们调用 shutdown() 方法关闭线程池。注意,在使用 Spring 框架中的 ThreadPoolTaskExecutor 类创建线程池时,我们需要先调用 initialize() 方法进行初始化。
ThreadPoolTaskExecutor 底层还是通过 JDK 中提供的 ThreadPoolExecutor 类实现的。
线程池优点详解
线程池相比于线程来说,它不需要频繁的创建和销毁线程,线程一旦创建之后,默认情况下就会一直保持在线程池中,等到有任务来了,再用这些已有的线程来执行任务,如下图所示:
优点1:复用线程,降低资源消耗
线程在创建时要开辟虚拟机栈、本地方法栈、程序计数器等私有线程的内存空间,而销毁时又要回收这些私有空间资源,如下图所示:
而线程池创建了线程之后就会放在线程池中,因此线程池相比于线程来说,第一个优点就是可以复用线程、减低系统资源的消耗。
优点2:提高响应速度
线程池是复用已有线程来执行任务的,而线程是在有任务时才新建的,所以相比于线程来说,线程池能够更快的响应任务和执行任务。
优点3:管控线程数和任务数
线程池提供了更多的管理功能,这里管理功能主要体现在以下两个方面:
- 控制最大并发数:线程池可以创建固定的线程数,从而避免了无限创建线程的问题。当线程创建过多时,会导致系统执行变慢,因为 CPU 核数是一定的、能同时处理的任务数也是一定的,而线程过多时就会造成线程恶意争抢和线程频繁切换的问题,从而导致程序执行变慢,所以合适的线程数才是高性能运行的关键。
- 控制任务最大数:如果任务无限多,而内存又不足的情况下,就会导致程序执行报错,而线程池可以控制最大任务数,当任务超过一定数量之后,就会采用拒绝策略来处理多出的任务,从而保证了系统可以健康的运行。
优点4:更多增强功能
线程池相比于线程来说提供了更多的功能,比如定时执行和周期执行等功能。
小结
线程池是一种管理和复用线程资源的机制。相比于线程,它具备四个主要优势:1.复用线程,降低了资源消耗;2.提高响应速度;3.提供了管理线程数和任务数的能力;4.更多增强功能。
相关文章:

为什么要用线程池?
线程池是一种管理和复用线程资源的机制,它由一个线程池管理器和一组工作线程组成。线程池管理器负责创建和销毁线程池,以及管理线程池中的工作线程。工作线程则负责执行具体的任务。 线程池的主要作用是管理和复用线程资源,避免了线程的频繁…...

c语言的预处理和编译
预处理 文件包含 当预处理器发现#include指令时,会查看后面的文件名并把文件的内容包含到当前文件中 两种写法 尖括号:引用的是编译器的库路径里面的头文件。 双引号:引用的是程序目录中相对路径中的头文件,如果找不到再去上面…...

网络安全必学 SQL 注入
1.1 .Sql 注入攻击原理 SQL 注入漏洞可以说是在企业运营中会遇到的最具破坏性的漏洞之一,它也是目前被利用得最多的漏洞。要学会如何防御 SQL 注入,首先我们要学习它的原理。 针对 SQL 注入的攻击行为可描述为通过在用户可控参数中注入 SQL 语法&#x…...
Docker基础知识详解
✅作者简介:热爱Java后端开发的一名学习者,大家可以跟我一起讨论各种问题喔。 🍎个人主页:Hhzzy99 🍊个人信条:坚持就是胜利! 💞当前专栏:文章 🥭本文内容&am…...

腾讯、阿里入选首批“双柜台证券”,港股市场迎盛夏升温?
6月5日,香港交易所发布公告,将于6月19日在香港证券市场推出“港币-人民币双柜台模式”,当日确定有21只证券指定为双柜台证券。同时,港交所还表示,在双柜台模式推出前,更多证券或会被接纳并加入双…...
CentOS7 使用Docker 安装MySQL
CentOS7 使用Docker 安装MySQL Docker的相关知识本篇不会再概述,有疑惑的同学请自行查找相关知识。本篇只是介绍如何在CentOS7下使用Docker安装相应的镜像。 可登陆Docker官网 https://docs.docker.com 之后可以跟着官方的步骤进行安装。 clipboard.png 具体安装过…...
注解和反射复习
注解 注解:给程序和人看的,被程序读取,jdk5.0引用 内置注解 override:修饰方法,方法声明和重写父类方法, Deprecated:修饰,不推荐使用 suppressWarnings用来抑制编译时的警告,必须添加一个或多个参数s…...
RocketMQ的demo代码
下面是一个使用Java实现的RocketMQ示例代码,用于发送和消费消息: 首先,您需要下载并安装RocketMQ,并启动NameServer和Broker。 接下来,您可以使用以下示例代码来发送和消费消息: Producer.java文件&…...
C++ 连接、操作postgreSQL(基于libpq库)
C++ 连接postgreSQL(基于libpq库) 1.环境2.数据库操作2.1. c++ 连接数据库2.2. c++ 删除数据库属性表内容2.3. c++ 插入数据库属性表内容2.4 c++ 关闭数据库1.环境 使用libpq库来链接postgresql数据库,主要用到的头文件是这个: #include "libpq-fe.h"2.数据库操…...
Node.js技术简介及其在Web开发中的应用
Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,使得JavaScript能够在服务器端运行。Node.js采用事件驱动、非阻塞I/O模型,能够处理大量并发请求,非常适合处理I/O密集型的应用程序。本文将介绍Node.js的特点、优势以及在Web开发中的应…...
时间序列分析:原理与MATLAB实现
2023年9月数学建模国赛期间提供ABCDE题思路加Matlab代码,专栏链接(赛前一个月恢复源码199,欢迎大家订阅):http://t.csdn.cn/Um9Zd 目录 1. 时间序列分析简介 2. 自回归模型(AR) 2.1. 参数估计 2.2. MATLAB实现...
mysql排序之if(isnull(字段名),0,1),字段名 或者 if(isnull(字段名),1,0),字段名
mysql排序之if(isnull(字段名),0,1),字段名 或者 if(isnull(字段名),1,0),字段名 默认情况下,MySQL将null算作最小值。如果想要手动指定null的顺序,可以这样处理: 将null强制放在最前 //null, null, 1,2,3,4(默认就是这样&#…...

华为OD机试真题 Java 实现【递增字符串】【2023Q1 200分】,附详细解题思路
一、题目描述 定义字符串完全由“A’和B"组成,当然也可以全是"A"或全是"B。如果字符串从前往后都是以字典序排列的,那么我们称之为严格递增字符串。 给出一个字符串5,允许修改字符串中的任意字符,即可以将任何的"A"修改成"B,也可以将…...

合并文件解决HiveServer2内存溢出方案
一、文件过多导致HiveServer2内存溢出 1.1查看表文件个数 desc formatted yanyu.tmp• 表文件数量为6522102 1.2查看表文件信息 hadoop fs -ls warehouse/yanyu.db/tmp• 分区为string 类型的time字段,分了2001个区。 1.3.查看某个分区下的文件个数为10000个 …...

韧性数据安全体系缘起与三个目标 |CEO专栏
今年4月,美创科技在数据安全领域的新探索——“韧性”数据安全防护体系框架正式发布亮相。 为帮您更深入了解“韧性数据安全”,我们特别推出专栏“构建适应性进化的韧性数据安全体系”,CEO柳遵梁亲自执笔,进行系列解读分享。 首期…...
华为OD机试真题 Java 实现【火车进站】【牛客练习题】
一、题目描述 给定一个正整数N代表火车数量,0<N<10,接下来输入火车入站的序列,一共N辆火车,每辆火车以数字1-9编号,火车站只有一个方向进出,同时停靠在火车站的列车中,只有后进站的出站了,先进站的才能出站。 要求输出所有火车出站的方案,以字典序排序输出。 …...

c#快速入门(下)
欢迎来到Cefler的博客😁 🕌博客主页:那个传说中的man的主页 🏠个人专栏:题目解析 🌎推荐文章:题目大解析2 目录 👉🏻Inline和lambda委托和lambda 👉…...

基于深度学习的目标姿态检测方法_kaic
目录 摘要 第1章 引言 1.1 研究背景和意义 1.2 国内外研究现状 1.3 主要内容 第2章 单目相机的目标姿态检测技术 2.1单目相机的工作原理 2.2目标姿态检测 2.3已有的目标姿态检测方法及其局限性 2.4本章总结 第3章 构建数据集 3.1 数据集来源 3.2数据集标注 3.3数据集分析 3.4本…...

Pycharm设置Python每个文件开头自定义模板(带上声明字符编码、作者名、时间等)
Pycharm设置地址: 在File---settings---Editor---File and Code Templates---Python script 脚本里添加: 模板声明设置参考: # ---encoding:utf-8--- # Time : ${DATE} ${HOUR}:${MINUTE} # Author : 作者名 # Email :你的邮箱 # Sit…...
Gem相关操作命令
Gem相关操作命令 gem -v # 查看 gem 版本gem source # 查看 gem 配置源 gem source -l # 查看 gem 配置源目录 gem sources -a url # 添加 gem 配置源(url 需换成网址) gem sources --add url # 添加 gem 配置源(url 需换成网址)…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...