JavaEE之线程池
前面我们了解了多个任务可以通过创建多个线程去处理,达到节约时间的效果,但是每一次的线程创建和销毁也是会消耗计算机资源的,那么我们是否可以将线程进阶一下,让消耗计算机的资源尽可能缩小呢?线程池可以达到此效果,今天我们对 《线程池》 一探究竟!
1. 何为线程池?
线程池(Thread Pool)是一种并发编程的技术,用于在应用程序启动时创建一定数量的线程,并将它们保存在线程池中,以便于任务的执行和线程的重用。当有新任务到来时,线程池会分配一个空闲线程来执行该任务,任务完成后,线程不会被销毁,而是返回线程池中,等待执行下一个任务。
2. 为什么要用线程池?
为什么要用线程池,那就得从线程池的优点来说了
优点:
- 重用线程:避免了频繁创建和销毁线程的开销,提高了线程的利用率。
- 控制并发度:可以限制并发执行的线程数量,防止系统过载。
- 提供线程管理和监控:方便开发人员进行线程的管理和调试。
- 提供任务队列:实现任务的缓冲和调度,提升系统响应速度。
3. 为什么使用线程池可以提升效率?
由于线程的频繁创建和销毁会影响计算机效率,所以我们可以减少线程的频繁创建和销毁来提高计算机效率,因为线程池可以实现这种效果,所以可以提升效率,因为线程池做的是少量创建,少量销毁,进而做到了提升效率的功能
线程池最⼤的好处就是减少每次启动、销毁线程的损耗。
从另一种方面来说,计算机分为 内核态(操作系统层面) 和 用户态JVM层面(应用程序层),创建和销毁线程是内核态的操作
4. 线程池怎么用?
Java当中JDK给我们提供了一组针对不同使用场景的线程池实例,如下:
//1.用来处理大量短时间工作任务的线程池,如果池中没有可用的线程将创建新的线程,如果线程空闲60秒将回收并移除缓存
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//2.创建一个操作无界队列且固定大小线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
//3.创建一个操作无界队列且只有一个工作线程的线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
//4.创建一个单线程执行器,可以在给定时间后执行或定期执行
ScheduledExecutorService singleThreadScheduledExecutor=Executors.newSingleThreadScheduledExecutor();
//5.创建一个指定大小的线程池,可以在给定时间后执行或定期执行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
//6.创建一个指定大少(不传入参数,为当煎机器CPU核心数)的线程池,并行地处理任务
Executors.newWorkStealingPool();
说明:
- 使用Executors.newFixedThreadPool(3)能创建出固定包含3个线程的线程池.
- newCachedThreadPool:创建线程数目动态增长的线程池.
- newFixedThreadPool:创建固定线程数的线程池 ,返回值类型为ExecutorService.
- newSingleThreadExecutor: 创建只包含单个线程的线程池.
- newSingleScheduledThreadPool:创建一个单线程执行器,设定延迟时间后执行命令,或者定期执行命令,是进阶版的Timer.
- newScheduledThreadPool:创建一个指定大小的线程池,设定延迟时间后执行命令,或者定期执行命令.是进阶版的Timer.
- 无界:任务队列的容量 没有限制称为无界队列
- Executors本质上是ThreadPoolExecutor类的封装.


5. 自我实现一个线程池
思路:
- 首先要描述任务
通过Runnable描述任务
- 通过一个阻塞队列管理任务
//阻塞队列组织任务,最多处理100个任务
public static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(100);
- 提供一个方法向线程池提交任务
//添加任务到阻塞队列当中public void submit(Runnable runnable) throws InterruptedException {if(runnable==null){throw new IllegalAccessError("任务为空");}queue.put(runnable);}
- 创建多个线程,不停的扫描队列中的任务
//threadNum为初始化时,给定的线程池中含有线程的个数
public MyThreadPool(int threadNum) {if(threadNum<=0){throw new RuntimeException("线程数量必须大于0");}for (int i = 0; i < threadNum; i++) {Thread thread=new Thread(()->{//不停的扫描线程while (true) {try {//从线程中取出任务Runnable runnable = queue.take();//执行任务runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}});//启动线程thread.start();}}
- 测试我们的线程池是否成功
public class Test {public static void main(String[] args) throws InterruptedException {//创建线程数量为3的线程池MyThreadPool myThreadPool=new MyThreadPool(3);//向线程池提交10个任务for (int i = 0; i < 10; i++) {int taskId=i+1;myThreadPool.submit(new Runnable() {@Overridepublic void run() {System.out.println("执行任务"+taskId+", "+Thread.currentThread().getName());}});}}
}
- 完整的自我线程池如下:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;public class MyThreadPool {//阻塞队列组织任务,最多处理100个任务public static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(100);//添加任务到阻塞队列当中public void submit(Runnable runnable) throws InterruptedException {if(runnable==null){throw new IllegalAccessError("任务为空");}queue.put(runnable);}public MyThreadPool(int threadNum) {if(threadNum<=0){throw new RuntimeException("线程数量必须大于0");}for (int i = 0; i < threadNum; i++) {Thread thread=new Thread(()->{//不停的扫描线程while (true) {try {//从线程中取出任务Runnable runnable = queue.take();//执行任务runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}});//启动线程thread.start();}}
}
6. 创建系统自带的线程池

执行流程:
- 添加任务,核心线程从队列中取任务去执行
- 核心线程都在工作时,再添加的任务会进入到阻塞队列
- 阻塞队列满了后,会创建临时线程
- 阻塞队列满了并且临时线程达到最大,执行拒绝策略
一次性创建最大的线程数(根据机器的配置,比如CPU核数)
图解:

说明:
- corePoolSize: 核心线程的数量.(类似于正式员⼯,⼀旦录⽤,永不辞退)
- maximumPoolSize:线程池中最大的线程数=核心线程+临时线程的数目.(类似于临时⼯:⼀段时间不⼲活,就被辞退)
- keepAliveTime:临时线程存活的时间
- unit:临时线程存活的时间单位,是秒,分钟,还是其他值
- workQueue:组织(保存)任务的队列
- threadFactory: 创建线程的工厂,参与具体的创建线程⼯作.通过不同线程工厂创建出的线程相当于对一些属性进行了不同的初始化设置
- RejectedExecutionHandler: 拒绝策略,如果任务量超出线程池的负荷了接下来怎么处理

接下来我们探讨一下这四种拒绝策略:
1. AbortPolicy(): 超过负荷,直接抛出异常.
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class TestAbortPolicy {public static void main(String[] args) throws InterruptedException {ThreadPoolExecutor reject1 =new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,new LinkedBlockingQueue<>(10),new ThreadPoolExecutor.AbortPolicy());for (int i = 0; i < 100; i++) {int taskId = i + 1;reject1.submit(() -> {System.out.println("执行任务:" + taskId + ", " + Thread.currentThread().getName());});}}
}

举个例子: 现在我在和我的女友玩游戏,老师让我帮他做一项报告,我直接拒绝了,并抛出异常,我不做!!
2. CallerRunsPolicy():返回给调⽤者负责处理多出来的任务.
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class TestCallerRunsPolicy {public static void main(String[] args) {ThreadPoolExecutor reject2=new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,new LinkedBlockingQueue<>(10),new ThreadPoolExecutor.CallerRunsPolicy());for (int i = 0; i < 100; i++) {int taskId = i + 1;reject2.submit(()->{System.out.println("执行任务:" + taskId + ", " + Thread.currentThread().getName());});}}
}

举个例子: 现在我在和我的女友玩游戏,老师让我帮他做一项报告,我直接拒绝了,老师就自己去做了,保证了任务至少完成了。
3. DiscardOldestPolicy():丢弃队列中最⽼的任务.
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class TestDiscardOldestPolicy {public static void main(String[] args) {ThreadPoolExecutor reject2=new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,new LinkedBlockingQueue<>(10),new ThreadPoolExecutor.DiscardOldestPolicy());for (int i = 0; i < 100; i++) {int taskId = i + 1;reject2.submit(()->{System.out.println("执行任务:" + taskId + ", " + Thread.currentThread().getName());});}}
}

举个例子: 现在我在和我的女友玩游戏,老师让我帮他做一项报告,我直接退出游戏(不处理最老的任务),去完成老师交给我的任务。
4. DiscardPolicy():丢弃新来的任务.
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class TestDiscardPolicy {public static void main(String[] args) {ThreadPoolExecutor reject2=new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,new LinkedBlockingQueue<>(10),new ThreadPoolExecutor.DiscardPolicy());for (int i = 0; i < 100; i++) {int taskId = i + 1;reject2.submit(()->{System.out.println("执行任务:" + taskId + ", " + Thread.currentThread().getName());});}}
}

举个例子: 现在我在和我的女友玩游戏,老师让我帮他做一项报告,我直接拒绝了,老师也不做,日后可能忘记了该任务,再也找不回来。
总结: 在实际的开发过程中,我们要根据实际的业务场景选择不同的拒绝策略!!!
以上就是线程池的基本知识了,希望对你有帮助,谢谢!!
相关文章:
JavaEE之线程池
前面我们了解了多个任务可以通过创建多个线程去处理,达到节约时间的效果,但是每一次的线程创建和销毁也是会消耗计算机资源的,那么我们是否可以将线程进阶一下,让消耗计算机的资源尽可能缩小呢?线程池可以达到此效果&a…...
java 中 main 方法使用 KafkaConsumer 拉取 kafka 消息如何禁止输出 debug 日志
pom 依赖: <dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId><version>2.5.14.RELEASE</version> </dependency> 或者 <dependency><groupId>org.ap…...
【后端面试总结】Golang可能的内存泄漏场景及应对策略
Golang可能的内存泄漏场景及应对策略 一、引言 Golang作为一种高性能、并发友好的编程语言,其内置的垃圾回收机制极大地简化了内存管理。然而,这并不意味着开发者可以完全忽视内存泄漏问题。在实际开发中,由于不当的资源管理、循环引用、以…...
Java 反射机制详解
在 Java 编程世界中,反射机制犹如一把神奇的钥匙,它能够打开许多隐藏在代码深处的 “大门”,让开发者突破常规的限制,实现一些极具灵活性的功能。今天,就跟随我一同深入探究 Java 反射机制的奥秘。 一、什么是反射 反…...
【k8s】scc权限 restricted、anyuid、privileged
文章目录 概述1. 内置的scc2. OpenShift如何确定pod的scc2.1 Pod未带SCC标签的情况2.2. Pod带有SCC标签的情况 参考 概述 在OpenShift(后文简称OCP)中,很早就一个概念:Security Context Constraints ,简称SCC…...
2025华数杯国际赛A题完整论文讲解(含每一问python代码+数据+可视化图)
大家好呀,从发布赛题一直到现在,总算完成了2025“华数杯”国际大学生数学建模竞赛A题Can He Swim Faster的完整的成品论文。 本论文可以保证原创,保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文…...
ThreadLocal 的使用场景
在现代电商平台中,ThreadLocal 常用于以下场景,特别是与线程隔离相关的业务中,以提高性能和简化上下文传递。 1. 用户上下文信息管理 场景:在用户发起的每次请求中,需要携带用户 ID、角色、权限等信息,而这…...
后端开发 Springboot整合Redis Spring Data Redis 模板
目录 redis 配置 RedisConfig 类 完整代码 代码讲解 1. 类定义和注解 2. 定义 RedisTemplate Bean 3. 配置 JSON 序列化 4. 配置 Redis 的 key 和 value 序列化方式 5. 完成配置并返回 RedisTemplate 总结 redis 服务接口实现类 类级别 注入 RedisTemplate 常用 Re…...
代码随想录算法训练营第 4 天(链表 2)| 24. 两两交换链表中的节点19.删除链表的倒数第N个节点 -
一、24. 两两交换链表中的节点 题目:24. 两两交换链表中的节点 - 力扣(LeetCode) 视频:帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点_哔哩哔哩_bilibili 讲解:代码随想录 dummy-…...
【RDMA学习笔记】1:RDMA(Remote Direct Memory Access)介绍
从帝国理工的PPT学习。 什么是RDMA Remote Direct Memory Access,也就是Remote的DMA,是一种硬件机制,能直接访问远端结点的内存,而不需要处理器介入。 其中: Remote:跨node进行数据传输Directÿ…...
网络安全常见的35个安全框架及模型
大家读完觉得有帮助记得关注和点赞!!! 01、概述 网络安全专业机构制定的一套标准、准则和程序,旨在帮助组织了解和管理面临的网络安全风险。优秀的安全框架及模型应该为用户提供一种可靠方法,帮助其实现网络安全建设…...
Elasticsearch介绍及使用
Elasticsearch 是一款基于 Lucene 库构建的开源、分布式、RESTful 风格的搜索引擎和分析引擎,具有强大的全文搜索、数据分析、机器学习等功能,广泛应用于日志分析、实时数据分析、全文检索等场景。 核心概念 索引(Index)…...
Leetocde516. 最长回文子序列 动态规划
原题链接:Leetocde516. 最长回文子序列 class Solution { public:int longestPalindromeSubseq(string s) {int n s.size();vector<vector<int>> dp(n, vector<int>(n, 1));for (int i 0; i < n; i) {dp[i][i] 1;if (i 1 < n &&…...
iOS 逆向学习 - Inter-Process Communication:进程间通信
iOS 逆向学习 - Inter-Process Communication:进程间通信 一、进程间通信概要二、iOS 进程间通信机制详解1. URL Schemes2. Pasteboard3. App Groups 和 Shared Containers4. XPC Services 三、不同进程间通信机制的差异四、总结 一、进程间通信概要 进程间通信&am…...
高级生化大纲
一,蛋白质化学: 蛋白质分离是生物化学和分子生物学研究中的一项基本技术,用于根据蛋白质的物理和化学特性将其从混合物中分离出来。 1. 离心分离法 离心分离法利用离心力来分离不同质量或密度的颗粒和分子。 差速离心:通过逐…...
YARN WebUI 服务
一、WebUI 使用 与HDFS一样,YARN也提供了一个WebUI服务,可以使用YARN Web用户界面监视群集、队列、应用程序、服务、流活动和节点信息。还可以查看集群详细配置的信息,检查各种应用程序和服务的日志。 1.1 首页 浏览器输入http://node2.itc…...
【Unity3D】利用IJob、Burst优化处理切割物体
参考文章: 【Unity】切割网格 【Unity3D】ECS入门学习(一)导入及基础学习_unity ecs教程-CSDN博客 【Unity3D】ECS入门学习(十二)IJob、IJobFor、IJobParallelFor_unity ijobparallelfor-CSDN博客 工程资源地址&…...
【大前端】Vue3 工程化项目使用详解
目录 一、前言 二、前置准备 2.1 环境准备 2.1.1 create-vue功能 2.1.2 nodejs环境 2.1.3 配置nodejs的环境变量 2.1.4 更换安装包的源 三、工程化项目创建与启动过程 3.1 创建工程化项目 3.2 项目初始化 3.3 项目启动 3.4 核心文件说明 四、VUE两种不同的API风格 …...
基于文件系统分布式锁原理
分布式锁:在一个公共的存储服务上打上一个标记,如Redis的setnx命令,是先到先得方式获得锁,ZooKeeper有点像下面的demo,比较大小的方式判决谁获得锁。 package com.ldj.mybatisflex.demo;import java.util.*; import java.util.co…...
简历整理YH
一,订单中心 1,调拨单 融通(Rocketmq)-订单中心:ECC_BMS123(已出单),125(分配),127(发货),129(收货) 通过RocketMq接入多场景订单数据 2,销售单 sap(FTP)-订单中心,下发1002,1003,…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
