java线程池详解
在Java中,线程池是一种重要的多线程处理方式,通过管理和复用线程,提高应用程序的性能和响应速度,减少线程创建和销毁的开销,避免线程数量过多导致系统负载过高的问题。本文将详细介绍Java线程池的概念、核心参数、工作流程、常见类型、拒绝策略以及使用方法和优化建议。
一、线程池的概念
线程池就是线程的池子,用来管理和复用线程。它可以在应用程序中有效地管理线程的生命周期、调度和执行。线程池包含一组预先创建的线程,这些线程可以被动态分配给执行任务,从而避免了不断创建和销毁线程的开销。线程池通常用于执行大量的异步任务,提高多线程程序的性能和稳定性。
二、线程池的核心参数
线程池的核心参数包括:
- corePoolSize(核心线程数):线程池中保持的最小线程数,即使线程是空闲的。这些线程在处理任务时不会被回收,除非设置了allowCoreThreadTimeOut(true)来允许核心线程在空闲时被回收。
- maximumPoolSize(最大线程数):线程池允许的最大线程数,包括核心线程和非核心线程。当任务队列已满且活动线程数小于最大线程数时,会创建新的线程。
- keepAliveTime(线程空闲时间):非核心线程的空闲时间超过这个值就会被回收。指定非核心线程空闲线程的最长存活时间。
- unit(时间单位):用于指定keepAliveTime的时间单位,可以是TimeUnit.MILLISECONDS等。
- workQueue(任务队列):用于保存等待执行的任务。选择合适的任务队列,例如LinkedBlockingQueue、ArrayBlockingQueue等,以满足需求。
- threadFactory(线程工厂):用于创建新线程。通过线程工厂可以给每个创建出来的线程设置更有意义的名字。
- handler(拒绝策略):当队列和线程池都满了,说明线程池处于饱和状态,必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。还可以选择CallerRunsPolicy(用调用者所在线程来运行任务)、DiscardPolicy(丢弃队列里最近的一个任务,并执行当前任务)、DiscardOldestPolicy(丢弃最老的任务,尝试重新提交新的任务)等策略,或者根据应用场景实现RejectedExecutionHandler接口自定义策略。
三、线程池的工作流程
线程池的工作流程如下:
- 当有新任务来时,将先使用核心线程执行。
- 当任务数达到核心线程数时,后续的任务会被放入任务队列中等待执行。
- 如果任务队列已满,且活动线程数小于最大线程数,会创建新的非核心线程来执行任务。
- 当任务数达到最大线程数时,线程池满了,如果有新的任务,将执行拒绝策略。
四、常见线程池类型
Java中常见的线程池类型包括:
- FixedThreadPool(固定大小线程池):包含固定数量的线程,适用于需要限制并发线程数量的场景。
- CachedThreadPool(缓存线程池):不固定线程数量,可以根据需要自动创建新线程,适用于短期异步任务。
- SingleThreadPool(单线程池):只包含一个工作线程,保证所有任务按顺序执行,适用于需要保持任务顺序执行的场景。
- ScheduledThreadPool(定时线程池):可以执行定时任务和周期性任务。
- WorkStealingPool(工作窃取线程池):Java 8中引入的一种新类型的线程池,主要用于处理耗时任务,适用于需要大量并行任务、任务之间没有依赖关系的情况。
五、线程池的使用
Java提供了ThreadPoolExecutor类来实现线程池的管理。以下是使用ThreadPoolExecutor创建线程池并提交任务的示例代码:
import java.util.concurrent.*; public class ThreadPoolExample { public static void main(String[] args) { // 创建线程池 ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, // 核心线程数 4, // 最大线程数 60, // 线程空闲时间 TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>() ); // 向线程池提交任务 for (int i = 0; i < 10; i++) { final int task = i; executor.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 正在执行第 " + (task + 1) + " 个任务"); } }); } // 关闭线程池 executor.shutdown(); }
}
此外,Java还提供了Executors工厂类来方便地创建常见的线程池类型。以下是使用Executors创建固定大小线程池、缓存线程池、单线程池和定时线程池的示例代码:
import java.util.concurrent.*; public class ExecutorsExample { public static void main(String[] args) { // 创建固定大小线程池 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); // 创建缓存线程池 ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); // 创建单线程池 ExecutorService singleThreadPool = Executors.newSingleThreadExecutor(); // 创建定时线程池 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); // 向线程池提交任务(示例) for (int i = 0; i < 3; i++) { final int task = i; fixedThreadPool.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 正在执行固定大小线程池中的第 " + (task + 1) + " 个任务"); } }); cachedThreadPool.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 正在执行缓存线程池中的第 " + (task + 1) + " 个任务"); } }); singleThreadPool.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 正在执行单线程池中的第 " + (task + 1) + " 个任务"); } }); } // 定时任务示例 scheduledThreadPool.schedule(new Runnable() { @Override public void run() { System.out.println("定时任务执行"); } }, 2, TimeUnit.SECONDS); // 关闭线程池(示例) fixedThreadPool.shutdown(); cachedThreadPool.shutdown(); singleThreadPool.shutdown(); scheduledThreadPool.shutdown(); }
}
六、线程池的拒绝策略
当线程池和队列都满了时,需要采取拒绝策略来处理新的任务。Java线程池支持多种拒绝策略,包括:
- AbortPolicy:直接抛出异常,防止系统崩溃。
- CallerRunsPolicy:在提交者线程中执行任务。
- DiscardPolicy:直接丢弃新任务。
- DiscardOldestPolicy:丢弃最老的任务,尝试重新提交新的任务。
选择合适的拒绝策略,可以避免任务丢失或者对系统造成过度负荷的影响。
七、线程池的优化建议
- 合理设置线程池大小:根据任务类型、执行时间和系统负载等因素来确定线程池大小。如果任务是I/O密集型,可以适当增加线程池大小;如果任务是计算密集型,可以适当减少线程池大小。
- 使用有界队列:无界队列可能会导致内存溢出,因此建议使用有界队列,并根据实际情况选择合适的拒绝策略。
- 动态调整线程池大小:通过调整keepAliveTime的值来动态调整线程池大小。例如,当任务量较少时,可以把keepAliveTime设置较长,让多余的线程等待更长时间以便对突发任务做出快速响应。
- 及时移除空闲线程:保持线程池中的空闲线程数量最小,可以减少系统资源开销。
- 避免线程池饥饿:线程池饥饿会导致任务一直处于排队状态,无法得到处理。可通过调整线程池大小、队列类型和拒绝策略等来避免线程池饥饿。
相关文章:
java线程池详解
在Java中,线程池是一种重要的多线程处理方式,通过管理和复用线程,提高应用程序的性能和响应速度,减少线程创建和销毁的开销,避免线程数量过多导致系统负载过高的问题。本文将详细介绍Java线程池的概念、核心参数、工作…...
五、创建型(建造者模式)
建造者模式 概念 建造者模式是一种创建型设计模式,通过使用多个简单的对象一步步构建一个复杂的对象。它将一个复杂对象的构建过程与其表示分离,从而使同样的构建过程可以创建不同的表示。 应用场景 复杂对象构建:当一个对象有多个属性&…...

CPU超线程技术是什么,怎么启用超线程技术
超线程技术是一种允许单个物理CPU核心模拟成两个逻辑核心的技术,从而提升处理器的并行性能和效率。以下是对超线程技术的详细介绍: 基本概念:超线程(Hyper-Threading,HT)是Intel公司研发的一种技术&#x…...
vba学习系列(7)--考勤表制作
系列文章目录 文章目录 系列文章目录前言一、汇总所有工作表指定区域内容到指定工作表二、汇总所有工作表指定区域内容到指定工作表(带公式)总结 前言 一、汇总所有工作表指定区域内容到指定工作表 Sub CopyRangesToSummary()Dim sourceSheet As WorksheetDim targetSheet As…...

Java学习第九天
相同包下的类可以直接访问,不同包下的类需要导包才可以使用,导包格式:import 包名.类名 final关键字: 常量: 枚举:一种特殊的类型(反编译之后本质就是实例常量,自己定义的类,创建了几…...

【算法系列-链表】链表相交 环形链表II
【算法系列-链表】链表相交&环形链表 文章目录 【算法系列-链表】链表相交&环形链表1. 链表相交1.1 思路分析🎯1.2 解题过程🎬1.3 代码示例🌰 2. 环形链表II2.1 思路分析🎯2.2 代码示例🌰 1. 链表相交 【题目…...

使用 Go 和 Gin 框架构建简单的用户和物品管理 Web 服务
使用 Go 和 Gin 框架构建简单的用户和物品管理 Web 服务 在本项目中,我们使用 Go 语言和 Gin 框架构建了一个简单的 Web 服务,能够管理用户和物品的信息。该服务实现了两个主要接口:根据用户 ID 获取用户名称,以及根据物品 ID 获…...

【VUE】双端比较算法
假设我们有两个虚拟节点 oldVnode 和 newVnode,它们分别对应的DOM结构为: 我们需要将 oldVnode 更新为 newVnode,这时就可以使用双端比较算法了。算法本质上是将新旧节点进行一次交叉比较,尽可能地重复使用已有的节点来达到最小…...

跨界的胜利:机器学习与神经网络的物理之光
近日,2024年诺贝尔物理学奖颁发给了机器学习与神经网络领域的研究者,这是历史上首次出现这样的情况。这项奖项原本只授予对自然现象和物质的物理学研究作出重大贡献的科学家,如今却将全球范围内对机器学习和神经网络的研究和开发作为了一种能…...
容器化技术:Docker的基本概念和使用
在现代软件开发和运维中,容器化技术已经成为一种不可或缺的工具。Docker作为容器化技术的代表,以其轻量级、可移植性和隔离性等特点,赢得了广泛的关注和应用。本文将详细介绍Docker的基本概念和使用方法,帮助读者快速上手Docker容…...

EcoVadis认证内容有哪些?EcoVadis认证申请流程?
EcoVadis认证是一个国际性的可持续发展评估平台,旨在帮助全球企业和供应链评鉴其在环境、社会和治理(ESG)方面的表现。该认证框架由法国的检验、认证和检测机构必维集团(Bureau Veritas)创建,得到了众多跨国…...

Windows 搭建 Gitea
一、准备工作 1. 安装 Git:Gitea 依赖 Git 进行代码管理,所以首先需要确保系统中安装了 Git。 下载地址:https://git-scm.com/downloads/win 2. 安装数据库(可选) 默认情况下,Gitea 使用 SQLite 作为内…...

嵌入式面试——FreeRTOS篇(五) 事件标志组
本篇为:FreeRTOS事件标志组篇 1、事件标志组介绍 答: 事件标志位:用一个位,来表示事件是否发生。 事件标志组是一组事件标志位的合集,可以简单的理解事件标志组,就是一个整数。 2、事件标志组的特点 答&am…...
智能听诊器:宠物健康管理的革命
智能听诊器不仅仅是一个简单的监测工具,它代表了宠物健康管理的一次革命。通过收集和分析宠物的生理数据,智能听诊器能够帮助宠物主人和医生更好地理解宠物的健康需求,从而提供更加个性化的护理方案。 智能听诊器通过高精度的传感器…...

dfs +剪枝sudoku———poj2676
目录 前言 lowbit函数 数独 suduku 问题描述 输入 输出 问题分析 子网格位置 优化搜索顺序剪枝1 优化搜索顺序剪枝2 可行性剪枝 代码 前言 lowbit函数 这是一个利用二进制位运算取出二进制数最后一位’1‘的函数 数独 数独大家肯定都玩过,…...
机器学习:关联规则:Apriori算法、FP - Growth算法的原理、应用场景及优缺点介绍
一、关联规则算法概述 关联规则挖掘是数据挖掘中的一个重要任务,用于发现数据集中不同项之间的关联关系。 二、Apriori算法 原理 频繁项集生成:Apriori算法基于一个先验原理,即如果一个项集是频繁的,那么它的所有子集也是频繁的…...
从0开始深度学习(7)——线性回归的简洁实现
在从0开始深度学习(5)——线性回归的逐步实现中,我们手动编写了数据构造模块、损失函数模块、优化器等,但是在现代深度学习框架下,这些已经包装好了 本章展示如果利用深度学习框架简洁的实现线性回归 0 导入头文件 im…...
【网络安全 | Java代码审计】华夏ERP(jshERP)v2.3
未经许可,不得转载。 文章目录 技术框架开发环境代码审计权限校验绕过SQL注入Fastjson反序列化命令执行存储型XSS越权/未授权重置密码越权/未授权删除用户信息越权/未授权修改用户信息会话固定安全建议项目地址:https://github.com/jishenghua/jshERP 技术框架 核心框架:Sp…...
Setting the value of ‘*‘ exceeded the quota
H5之localStorage限额报错quota_exceeded the quota-CSDN博客 Uncaught DOMException: Failed to set a named property on Storage: Setting the value of background exceeded the quota. 超出了 localStorage 的最大长度。...
前端页面模块修改成可动态生成数据模块——大部分数据为GPT生成(仅供学习参考)
前端页面模块修改成可动态生成数据模块: 这些案例展示了如何通过Blade模板将前端页面模块变成可动态生成的模板。通过巧妙使用Blade语法、控制结构、CSS/JS分离、组件复用等技巧,可以大大提高代码的灵活性和复用性。在Laravel的Controller中准备好数据并…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...

黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...