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

【JavaEE初阶】线程池

目录

📕 引言

🌳 概念

🍀ThreadPoolExecutor 类

🚩 int corePoolSize与int maximumPoolSize:

🚩 long keepAliveTime与TimeUnit nuit:

🚩 BlockingQueue workQueue:

🚩 ThreadFactory threadFactory:

🚩 RejectedExecutionHandler handler:

🎄标准库中的线程池

🏠 模拟实现线程池

🙂 多线程初阶总结

🚩 保证线程安全的大致思路:

🚩对比线程和进程

📌线程的优点

📌进程与线程的区别


📕 引言

之前呢我们对于并发编程,使用多线程就可以了,是因为线程比进程更轻量,在频繁创建和销毁的时候,更有优势,随着时代的发展,对于"频繁"二字有了新的认识。之前一个服务器 1s 处理 1k 个请求,就认为是频繁了。现在,一个服务器 1s 要处理几w的请求......

那如何优化呢?  我们就引入了线程池和协程(纤程)。本篇文章就来说说线程池,对于协程暂且不表,在Java8中还不支持,后序在高版本的Java中,引入的"虚拟线程"本质上就是协程。

为哈引入线程池或者协程就能够提升效率呢?

最关键的要点,直接创建/销毁线程,是需要在用户态+内核态配合完成的工作,对于线程池/协程,只需要在用户态即可,不需要内核态的配合。

那为什么说用户态+内核态配合完成就不够高效?

例子:

🌳 概念

线程池,是一种线程的使用模式,它为了降低线程使用中频繁的创建和销毁所带来的资源消耗与代价。

通过创建一定数量的线程,让他们时刻准备就绪等待新任务的到达,而任务执行结束之后再重新回来继续待命

想象这么一个场景:

假设有一个妹子,长得很好看并且又有才华,想要谈一个对象,如果妹子和这个对象谈腻歪了,就想要换一个,成本就比较高,效率就比较低,我需要先冷暴力他,消耗他的耐心,然后再提分手,分手完毕之后,还需要下一个小哥哥一点一点培养感情,这样效率确实很低。

为了提高效率,我就和在男朋友的交往过程中,提前和其他小哥哥搞暧昧,先把感情培养到位,这样,我只要和现男友分手,后面这个暧昧的小哥就可以直接转正。这样的小哥就称为"备胎",如果我需要频繁的更换男朋友,一个备胎不够用,就需要多搞几个,这就构成了"备胎池"。这样效率就提高了

所以字符串常量池,数据库连接池,线程池,进程池,内存池......思想都一样,用来提升效率。

线程池最核心的设计思路复用线程,平摊线程的创建与销毁的开销代价

相比于来一个任务创建一个线程的方式,使用线程池的优势体现在如下几点:

  • 避免了线程的重复创建与开销带来的资源消耗代价
  • 提升了任务响应速度,任务来了直接选一个线程执行而无需等待线程的创建
  • 线程的统一分配和管理,也方便统一的监控和调优

🍀ThreadPoolExecutor 类

标准库提供的线程池主要的类为:ThreadPoolExecutor

这个类使用起来比较复杂,构造方法很多,包含很多参数(面试考点,问这些参数是什么意思)。

在帮助手册java.util.concurrent(并发),这里面包含了很多多线程相关的工具或者是类

构造方法:这里面有四个构造方法,仔细观察发现里面的参数,越往下越全,所以我们只需要搞清楚最后一个,前三个也就清楚了。

这里面总共有7个参数,来说说这7个参数的意思:

🚩 int corePoolSize与int maximumPoolSize:

🚩 long keepAliveTime与TimeUnit nuit:

🚩 BlockingQueue<Runnable> workQueue:

🚩 ThreadFactory threadFactory:

🚩 RejectedExecutionHandler handler:

在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会有问题,那么这些溢出的任务,ThreadPoolExecutor为我们提供了拒绝任务的处理方式,以便在必要的时候按照我们的策略来拒绝任务

线程池拒绝任务的时机有以下两种:

  • 第一种情况是当我们调用 shutdown 等方法关闭线程池后,即便此时可能线程池内部依然有没执行完的任务正在执行,但是由于线程池已经关闭,此时如果再向线程池内提交任务,就会遭到拒绝。

  • 第二种情况是线程池没有能力继续处理新提交的任务,也就是工作已经非常饱和的时候

标准库提供了四个解决方案:

线程池任务拒绝策略实现了 RejectedExecutionHandler 接口,JDK 中自带了四种任务拒绝策略。分别是AbortPolicy、DiscardPolicy、DiscardOldestPolicy、CallerRunsPolicy。其中AbortPolicy是ThreadPoolExecutor默认使用。

1,AbortPolicy(默认)

这种拒绝策略在拒绝任务时,会直接抛出一个类RejectedExecutionException的RuntimeException,让你感知到任务被拒绝了,于是你便可以根据业务逻辑选择重试或者放弃提交等策略。

2,DiscardPolicy

这种拒绝策略正如它的名字所描述的一样,当新任务被提交后直接被丢弃掉,也不会给你任何的通知,相对而言存在一定的风险,因为我们提交的时候根本不知道这个任务会被丢弃,可能造成数据丢失。

3,DiscardOldestPolicy

如果线程池没被关闭且没有能力执行,则会丢弃任务队列中的头结点,通常是存活时间最长的任务,这种策略与第二种不同之处在于它丢弃的不是最新提交的,而是队列中存活时间最长的,这样就可以腾出空间给新提交的任务,但同理它也存在一定的数据丢失风险。

4,CallerRunsPolicy

相对而言它就比较完善了,当有新任务提交后,如果线程池没被关闭且没有能力执行,则把这个任务交于提交任务的线程执行,也就是谁提交任务,谁就负责执行任务。这样做主要有两点好处:
🎈第一点新提交的任务不会被丢弃,这样也就不会造成业务损失。
🎈第二点好处是,由于谁提交任务谁就要负责执行任务,这样提交任务的线程就得负责执行任务,而执行任务又是比较耗时的,在这段期间,提交任务的线程被占用,也就不会再提交新的任务,减缓了任务提交的速度,相当于是一个负反馈。在此期间,线程池中的线程也可以充分利用这段时间来执行掉一部分任务,腾出一定的空间,相当于是给了线程池一定的缓冲期。

总结:

🎄标准库中的线程池

由于标准库自己也知道ThreadPoolExecutor使用起来比较费劲,于是标准库自己提供了几个工厂类,对于上述线程池又进一步封装了.

在标准库里面提供了一个 Executors类,这个类就是标准库提供线程池的工厂类

有几个不同的版本:主要使用前面两个

注意上述方法是有返回值的,返回值类型为 ExecutorService

代码一:我们可以看到是一个单独的线程,并非跟主线程是一个线程

代码二:

  • 使用 Executors.newFixedThreadPool(10) 能创建出固定包含 10 个线程的线程池.

  • 返回值类型为 ExecutorService

  • 通过 ExecutorService.submit 可以注册一个任务到线程池中

🏠 模拟实现线程池

接下来我们简单模拟实现一个简单的线程池

  1. 创建MyThreadPool实现我们的线程池

  2. 使用阻塞队列组织所有任务

  3. 构造方法里创建相应大小的线程数

  4. 提供一个submit方法使用线程池里面的线程

代码:

测试:

🙂 多线程初阶总结

🚩 保证线程安全的大致思路:

1,使用没有共享资源的模型

2,适用共享资源只读,不写的模型

  • 不需要写共享资源的模型

  • 使用不可变对象

3,直面线程安全(重点)

  • 保证原子性

  • 保证顺序性

  • 保证可见性

🚩对比线程和进程

📌线程的优点

  1. 创建一个新线程的代价要比创建一个新进程小得多
  2. 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
  3. 线程占用的资源要比进程少很多
  4. 能充分利用多处理器的可并行数量
  5. 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
  6. 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
  7. I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作
📌进程与线程的区别
  1. 进程是系统进行资源分配和调度的一个独立单位,线程是程序执行的最小单位。

  2. 进程有自己的内存地址空间,线程只独享指令流执行的必要资源,如寄存器和栈。

  3. 由于同一进程的各线程间共享内存和文件资源,可以不通过内核进行直接通信。

  4. 线程的创建、切换及终止效率更高

相关文章:

【JavaEE初阶】线程池

目录 &#x1f4d5; 引言 &#x1f333; 概念 &#x1f340;ThreadPoolExecutor 类 &#x1f6a9; int corePoolSize与int maximumPoolSize&#xff1a; &#x1f6a9; long keepAliveTime与TimeUnit nuit&#xff1a; &#x1f6a9; BlockingQueue workQueue&#xff1a…...

zdpgo_cobra_req 新增解析请求体内容

zdpgo_cobra_req 使用Go语言开发的&#xff0c;类似于curl的HTTP客户端请求工具&#xff0c;用于便捷的测试各种HTTP地址 特性 1、帮助文档都是中文的2、支持常见的HTTP请求&#xff0c;比如GET、POST、PUT、DELETE等 下载 git clone https://github.com/zhangdapeng520/z…...

Java聚合快递对接云洋系统快递小程序源码

&#x1f31f;【一键聚合&#xff0c;高效便捷】快递对接云洋系统小程序全攻略&#x1f680; 引言&#xff1a;告别繁琐&#xff0c;拥抱智能快递新时代&#x1f50d; 在这个快节奏的时代&#xff0c;每一分每一秒都弥足珍贵。你是否还在为手动输入多个快递单号、频繁切换不同…...

陕西西安培华学院计算机软件工程毕业设计课题选题参考目录​

陕西西安培华学院计算机软件工程毕业设计课题选题 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#xff0c;阿里云开发社区乘风者计划专家博主&#xff0c;CSDN平台&#xff0c;✌️Java领域优质创作者,博客之星、掘金/华为云/阿里云等平台优质作者、专注于大学生项目实战开发…...

如何用sql在1分钟从1T数据中精准定位查询?Hive离线数仓 Spark分析

最近在一个群里&#xff0c;从群友哪里了解到这样一个业务需求&#xff1a;如何在 hdfs 1 T源数据库中&#xff0c;1分钟内从其中抓取自己想要的数据&#xff1f; 我的理解是 &#xff1a; 在hdfs数据库中为拥有 尽1T数据的表创建索引,并对其进行性能优化&#xff0c;以实现…...

acpi 主板布局需要 efi

今天在折腾 ESXI 的时候&#xff0c;启动虚拟机跳出了 acpi 主板布局需要 efi 然后我就将 ESXI 的启动方式改为了 EFI 但是虚拟机有莫名的启动不了&#xff0c;网上也没有找到办法&#xff0c;最后&#xff0c;我将虚拟机类型有原本的 ubuntu 换成了 debian 最后启动成功&…...

月之暗面对谈 Zilliz:长文本和 RAG 如何选择?

01 长文本与RAG通用对比 准确率&#xff1a;通常情况下长文本优于RAG 长文本&#xff1a;可更加综合的去分析所有相关的内容&#xff0c;提取相关数字&#xff0c;生成图表&#xff0c;效果尚可。RAG&#xff1a;更适合找到一段或者是几段可能相关的段落。如果希望大模型能够…...

高级java每日一道面试题-2024年8月12日-设计模式篇-请列举出在JDK中几个常用的设计模式?

如果有遗漏,评论区告诉我进行补充 面试官: 请列举出在JDK中几个常用的设计模式? 我回答: 在Java Development Kit (JDK) 中&#xff0c;许多设计模式被广泛使用&#xff0c;以帮助实现软件的结构、行为和复用。下面是一些在JDK中常见的设计模式及其简要说明&#xff1a; 工…...

mysql workbench8.0如何导出mysql5.7格式的sql定义

碰到的问题 mac上安装mysql workbech6.0后不能运行&#xff0c;但安装workbench8.0后&#xff0c;导出的数据库sql文件默认是msyql 8.0的语法和格式。比如生成索引的语句后面会有visible关键字&#xff0c;当把mysql8.0的sql文件导入到mysql5.7时就会报错。 如何解决 点击my…...

数据结构(学习)2024.8.6(顺序表)

今天开始学习数据结构的相关知识&#xff0c;大概分为了解数据结构、算法&#xff1b;学习线性表&#xff1a;顺序表、链表、栈、队列的相关知识和树&#xff1a;二叉树、遍历、创建&#xff0c;查询方法、排序方式等。 目录 一、数据结构 数据 逻辑结构 1.线性结构 2.树…...

MyBatis全解

目录 一&#xff0c; MyBatis 概述 1.1-介绍 MyBatis 的历史和发展 1.2-MyBatis 的特点和优势 1.3-MyBatis 与 JDBC 的对比 1.4-MyBatis 与其他 ORM 框架的对比 二&#xff0c; 快速入门 2.1-环境搭建 2.2-第一个 MyBatis 应用程序 2.3-配置文件详解 (mybatis-config.…...

【Redis进阶】Redis集群

目录 Redis集群的诞生 单节点Redis的局限性 1.存储容量限制 2.性能瓶颈 3.单点故障 4.扩展性能差 分布式系统发展的需要 1.海量数据处理 2.高性能要求 3.弹性扩展能力 Redis集群&#xff08;cluster&#xff09; 如图所示案例 Redis集群设计 什么是数据分片&…...

JVM运行时数据区之虚拟机栈

【1】概述 Java虚拟机栈&#xff08;Java Virtual Machine Stack&#xff09;&#xff0c;早期也叫Java栈。每个线程在创建时都会创建一个虚拟机栈&#xff0c;其内部保存一个个的栈帧&#xff08;Stack Frame&#xff09;&#xff0c;对应着一次次的Java方法调用。 栈是运行…...

Python 机器学习求解 PDE 学习项目 基础知识(4)PyTorch 库函数使用详细案例

PyTorch 库函数使用详细案例 前言 在深度学习中&#xff0c;PyTorch 是一个广泛使用的开源机器学习库。它提供了强大的功能&#xff0c;用于构建、训练和评估深度学习模型。本文档将详细介绍如何使用以下 PyTorch 相关库函数&#xff0c;并提供相应的案例示例&#xff1a; to…...

SpringBoot-enjoy模板引擎

主要用于Web开发&#xff0c;前后端不分离时的页面渲染 SpringBoot整合enjoy模板引擎步骤&#xff1a; 1.将页面保存在templates目录下 2.添加enjoy的坐标 <dependency> <groupId>com.jfinal</groupId> <artifactId>enjoy</artifactId&g…...

【学习笔记】如何训练大模型

如何在许多 GPU 上训练真正的大型模型&#xff1f; 单个 GPU 工作线程的内存有限&#xff0c;并且许多大型模型的大小已经超出了单个 GPU 的范围。有几种并行范式可以跨多个 GPU 进行模型训练&#xff0c;还可以使用各种模型架构和内存节省设计来帮助训练超大型神经网络。 并…...

高可用集群KEEPALIVED

一、集群相关概念简述 HA是High Available缩写&#xff0c;是双机集群系统简称&#xff0c;指高可用性集群&#xff0c;是保证业务连续性的有效解决方案&#xff0c;一般有两个或两个以上的节点&#xff0c;且分为活动节点及备用节点。 1、集群的分类 LB&#xff1a;负载均衡…...

Linux shell编程学习笔记69: curl 命令行网络数据传输工具 选项数量雷人(中)

0 前言 curl是Linux中的一款综合性网络传输工具&#xff0c;既可以上传也可以下载&#xff0c;支持HTTP、HTTPS、FTP等30余种常见协‍议。 该命令选项超多&#xff0c;在学习笔记68中&#xff0c;我们列举了该命令的部分实例&#xff0c;今天继续通过实例来研究curl命令的功能…...

怎么在网站底部添加站点地图?

在优化网站 SEO 时&#xff0c;站点地图&#xff08;Sitemap&#xff09;是一个非常重要的工具。它帮助搜索引擎更好地理解和抓取您的网站内容。幸运的是&#xff0c;从 WordPress 5.5 开始&#xff0c;WordPress 自带了站点地图生成功能&#xff0c;无需额外插件。下面将介绍如…...

bash和sh的区别

‌Bash和‌sh的主要区别在于它们的交互性、兼容性、默认shell以及脚本执行方式。 首先&#xff0c;Bash提供了更丰富的交互功能&#xff0c;使得它在终端中的使用更加舒适和方便。相比之下&#xff0c;sh由于其最小化的功能集&#xff0c;提供了更广泛的兼容性。然而&#xff…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径&#xff0c;但是vite中默认不可以。 如何实现&#xff1a; vite中提供了resolve.alias&#xff1a;通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台

淘宝扭蛋机小程序系统的开发&#xff0c;旨在打造一个互动性强的购物平台&#xff0c;让用户在购物的同时&#xff0c;能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机&#xff0c;实现旋转、抽拉等动作&#xff0c;增…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...

raid存储技术

1. 存储技术概念 数据存储架构是对数据存储方式、存储设备及相关组件的组织和规划&#xff0c;涵盖存储系统的布局、数据存储策略等&#xff0c;它明确数据如何存储、管理与访问&#xff0c;为数据的安全、高效使用提供支撑。 由计算机中一组存储设备、控制部件和管理信息调度的…...

算法250609 高精度

加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...

虚幻基础:角色旋转

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录 移动组件使用控制器所需旋转&#xff1a;组件 使用 控制器旋转将旋转朝向运动&#xff1a;组件 使用 移动方向旋转 控制器旋转和移动旋转 缺点移动旋转&#xff1a;必须移动才能旋转&#xff0c;不移动不旋转控制器…...