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

(史上最全)线程池

线程池

文章目录

    • 线程池
      • 一,前言
      • 二,线程池
      • 三,参数
      • 四,线程池的实现原理
      • 5.线程池的使用案例(自定义线程池)
      • 6.使用Executors 创建常见的功能线程池
        • 1.固定大小线程池
        • 2.定时线程
        • 3.可缓存线程池
        • 4.单线程化线程池

一,前言

虽然线程给我们程序带来了更高的执行效率,但是线程不是创建的越多越好,那么线程创建的过多,会带来什么问题呢?

首先线程的创建和销毁都是很耗时很浪费性能的操作

(new三五个Thread还好,我需要一千个线程呢?)

线程之间频繁的进行上下文切换,增加系统的负载

为了解决上述问题,线程池诞生了,线程池的核心思想就是:线程复用

也就是说线程用完后不销毁,放到池子里等着新任务的到来,反复利用N个线程来执行所有新老任务。这带来的开销只会是那N个线程的创建,而不是每来一个请求都带来一个线程的从生到死的过程。

二,线程池

概念

‌‌线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。‌ 线程池是一种线程复用的技术,可以有效地控制线程的数量,减少线程创建和销毁带来的开销,提高系统响应速度,并方便线程管理。(官方)

简单来说,线程池就是提前创建好一批线程,当有任务的时候,从池子中取出一个线程去执行该任务,执行结束后,再把线程放回池子中,以备循环使用。

三,参数

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,  long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {
}

参数解释

corePoolSize:核心线程数

线程池在完成初始化之后,默认情况下,线程池中不会有任何线程,线程池会等有任务来的时候
再去创建线程。核心线程创建出来后即使超出了线程保持的存活时间配置也不会销毁,核心线程
只要创建就永驻了,就等着新任务进来进行处理。

maximumPoolSize:最大线程数

核心线程忙不过来且任务存储队列满了的情况下,还有新任务进来的话就会继续开辟线程,但是
也不是任意的开辟线程数量,线程数(包含核心线程)达到最大线程数后就不会产生新线程了,
就会执行拒绝策略。

keepAliveTime:线程保持的存活时间

如果线程池当前的线程数多于核心线程数,那么如果多余的线程空闲时间超过线程保持的存活时
间,那么这些多余的线程(超出核心线程数的那些线程)就会被回收。

unit:线程保持的存活时间单位

比如:TimeUnit.MILLISECONDS、TimeUnit.SECONDS

workQueue:任务存储队列

核心线程数满了后还有任务继续提交到线程池的话,就先进入任务存储队列。

workQueue通常情况下有如下选择:
LinkedBlockingQueue:无界队列,意味着无限制,其实是有限制,大小是int的最大值。也可以
自定义大小。
ArrayBlockingQueue:有界队列,可以自定义大小,到了阈值就开启新线程(不会超过最大线
程数)。
SynchronousQueue: Executors.newCachedThreadPool();默认使用的队列。
一般都采取无界队列,因为他也可以设置大小,可以取代有界队列。

threadFactory:当线程池需要新的线程时,会用threadFactory来生成新的线程

默认采用的是 DefaultThreadFactory ,主要负责创建线程。 newThread() 方法。创建出来的
线程都在同一个线程组且优先级也是一样的。

handler:拒绝策略,任务量超出线程池的配置限制或执行shutdown还在继续提交任务的话,会执行handler 的逻辑。

默认采用的是 AbortPolicy ,遇到上面的情况,线程池将直接采取直接拒绝策略,也就是直接抛
出异常。 RejectedExecutionException

四种内置的拒绝策略
1. AbortPolicy(默认):直接抛出RejectedExecutionException异常,阻止系统正常运行。
2. CallerRunsPolicy:由调用线程(提交任务的线程)执行被拒绝的任务。这样做可以降低新任务
的提交速度,但可能会影响整体性能。
3. DiscardPolicy:默默地丢弃被拒绝的任务,不做任何处理。
4. DiscardOldestPolicy:丢弃最早被放入队列的任务,然后尝试重新提交被拒绝的任务。//自定义拒绝策略,实现RejectedExecutionHandler接口,并重写rejectedExecution方法来定义自
己的处理逻辑

四,线程池的实现原理

在这里插入图片描述

从图中我们可以看到完整的执行流程

  1. 线程提交到线程池
  2. 判断核心线程池是否已经达到设定的数量,如果没有达到,则直接创建线程执行任务
  3. 如果达到了,则放在队列中,等待执行
  4. 如果队列已经满了,则判断线程的数量是否已经达到设定的最大值,如果达到了,则直接执行拒绝策略
  5. 如果没有达到,则创建线程执行任务。

5.线程池的使用案例(自定义线程池)

import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {// 创建线程池ExecutorService executorService = new ThreadPoolExecutor(2,     //两个核心线程数4,     //最大线程数60,		// 线程保持的存活时间TimeUnit.SECONDS,//指定了 keepAliveTime 的单位为秒new ArrayBlockingQueue<>(10),//最多可以在这个队列中排队 10 个任务Executors.defaultThreadFactory(),// Java 提供的默认线程工厂来创建新线程new ThreadPoolExecutor.AbortPolicy());//拒绝策略// 提交任务for (int i = 0; i < 10; i++) {executorService.submit(() -> {//submit 方法:用于提交一个可执行的任务//() -> { ... }:表示一个实现了 Runnable 接口的匿名类。大括号内的代码是你希											望在独立线程中执行的逻辑。try {System.out.println("执行任务开始 " + Thread.currentThread().getName());Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}});}// 关闭线程池executorService.shutdown();}
}
//输出结果
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2

在输出中,pool-1-thread-1pool-1-thread-2 中的数字分别代表以下含义:

  1. pool-1:这是线程池的名称。1 表示这是第一个创建的线程池,如果有多个线程池,则会以递增的数字命名。
  2. thread-1thread-2:这些表示线程在该线程池中的编号。它们是按照创建顺序递增的。thread-1 是第一个线程,thread-2 是第二个线程,依此类推。

因此,整个字符串表示该线程池中的具体线程,帮助我们识别和调试哪个线程在执行哪个任务。

6.使用Executors 创建常见的功能线程池

Executors为我们封装好了 4 种常见的功能线程池如下:

  1. 定长线程(固定大小):FixedThreadPool
  2. 定时线程:ScheduledThreadPool
  3. 可缓存线程池:CachedThreadPool
  4. 单线程化线程池:SingleThreadExecutor
1.固定大小线程池

核心线程数和最大线程数是一样的,所以称之为固定线程数。
其他参数配置默认为:永不超时(0ms),无界队列( LinkedBlockingQueue )、默认线程工厂
( DefaultThreadFactory )、直接拒绝策略( AbortPolicy )。

public class ThreadPoolTest {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(2);for (int i = 0; i < 10; i++) {// 从结果中可以发现线程name永远都是两个。不会有第三个。executorService.execute(() -> System.out.println(Thread.currentThread().getName()));}}
}
2.定时线程

核心线程数手动传进来,最大线程数是Integer.MAX_VALUE,最大线程数是内部默认的,不可更改。
其他参数配置默认为:永不超时(0ns),带延迟功能的队列( DelayedWorkQueue )、默认线程工厂
( DefaultThreadFactory )、直接拒绝策略( AbortPolicy )。

public class ThreadPoolTest {public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService = Executors.newSchedul
edThreadPool(2);// 五秒一次scheduledExecutorService.schedule(() -> System.out.println(Thread.currentThread().getName()), 5, TimeUnit.SECONDS);// 首次五秒后执行,其次每隔1s执行一次scheduledExecutorService.scheduleAtFixedRate(() -> System.out.println(Thread.currentThread().getName()), 5, 1, TimeUnit.SECONDS);
}
3.可缓存线程池

他的功能是来个任务我就开辟个线程去处理,不会进入队列, SynchronousQueue 队列也不带存储元素
的功能。那这意味着来一亿个请求就会开辟一亿个线程去处理,keepAliveTime为60S,意味着线程空
闲时间超过60S就会被杀死;这就叫带缓存功能的线程池。
核心线程数是0,最大线程数是int的最大值,内部默认的,不可更改。

public class ThreadPoolTest {public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 10; i++) {// 从结果中可以发现线程name有10个。也就是有几个任务就会开辟几个线程。executorService.execute(() -
> System.out.println(Thread.currentThread().getName()));}}
}
4.单线程化线程池

核心线程数和最大线程数是1,内部默认的,不可更改,所以称之为单线程数的线程池。
类似于 Executors.newFixedThreadPool(1);
其他参数配置默认为:永不超时(0ms),无界队列( LinkedBlockingQueue )、默认线程工厂
( DefaultThreadFactory )、直接拒绝策略( AbortPolicy )。

public class ThreadPoolTest {public static void main(String[] args) {ExecutorService executorService = Executors.newSingleThreadExecutor();for (int i = 0; i < 10; i++) {// 从结果中可以发现线程name永远都是pool-1-thread-1。不会有第二个出现。executorService.execute(() -
> System.out.println(Thread.currentThread().getName()));}}
}

相关文章:

(史上最全)线程池

线程池 文章目录 线程池一&#xff0c;前言二&#xff0c;线程池三&#xff0c;参数四&#xff0c;线程池的实现原理5.线程池的使用案例(自定义线程池)6.使用Executors 创建常见的功能线程池1.固定大小线程池2.定时线程3.可缓存线程池4.单线程化线程池 一&#xff0c;前言 虽然…...

【ShuQiHere】 支持向量机(SVM)详解:从理论到实践,这一篇就够了

&#x1f4d6; 【ShuQiHere】 在现代机器学习课程中&#xff0c;支持向量机&#xff08;SVM&#xff09; 是不可或缺的一部分。它不仅在分类任务中有出色表现&#xff0c;还能灵活处理回归问题。尽管看似复杂&#xff0c;SVM 背后的思想却深刻而优雅。今天我们将全面探讨**支持…...

log4j2线程级动态日志级别

详见 参考 着重说明&#xff1a; DynamicThresholdFilter&#xff1a; 配置长这样&#xff1a;配置解释链接 <DynamicThresholdFilter key"logLevel" defaultThreshold"ERROR" onMatch"ACCEPT" onMismatch"DENY"><KeyVa…...

百度Android IM SDK组件能力建设及应用

作者 | 星途 导读 移动互联网时代&#xff0c;随着社交媒体、移动支付、线上购物等行业的快速发展&#xff0c;对即时通讯功能的需求不断增加。对于各APP而言&#xff0c;接入IM SDK&#xff08;即时通讯软件开发工具包&#xff09;能够大大降低开发成本、提高开发效率&#…...

CSS-Grid布局详解

前言 Grid 栅格布局 是 CSS 语言中非常强大的种布局&#xff0c;它提供了丰富的工具属性&#xff0c;可以轻松实现复杂且灵活的布局设计&#xff0c;因此想要完美使用CSS Grid 也有一定的难度和复杂性&#xff0c;我自己也是花了不少时间才真正掌握它的使用&#xff0c;在这篇…...

Give azure openai an encyclopedia of information

题意&#xff1a;给 Azure OpenAI 提供一部百科全书式的信息 问题背景&#xff1a; I am currently dabbling in the Azure OpenAI service. I want to take the default model and knowledge base and now add on to it my own unique information. So, for example, for mak…...

Nginx越界读取缓存漏洞(CVE-2017-7529)

漏洞原理&#xff1a; 影响版本内默认配置模块的Nginx只需要开启缓存&#xff0c;攻击者可以通过发送包含恶意构造range域的header请求进行远程攻击造成信息泄露。 影响范围&#xff1a; Nginx 0.5.6 – 1.13.2 漏洞复现&#xff1a; 开启靶场&#xff0c;访问8080端口 中间…...

【MySQL】查询语句之inner、left、right、full join 的区别

前言&#xff1a; INNER JOIN 和 OUTER JOIN 是SQL中常用的两种连接方式&#xff0c;用于从两表活多表中提取相关的数据。两者区别主要在于返回的 结果集 如何处理 匹配 与 不匹配 的行。 目录 1、INNER JOIN 2、OUTER JOIN 3、总结 1、INNER JOIN 称为内连接&#xff0c;只…...

Submariner 部署全过程

Submariner 部署全过程 部署集群配置 broker 集群&#xff1a; pod-cidr&#xff1a;11.244.0.0/16 service-cidr 11.96.0.0/12 broker 172.100.0.109 node 172.100.0.108 集群 1&#xff08; pve3 &#xff09;&#xff1a; pod-cidr&#xff1a;10.244.0.0/16 service-…...

驼峰命名法

一、驼峰命名法简介 驼峰命名法&#xff08;Camel Case&#xff09;是一种在编程和人类语言中广泛使用的书写方式&#xff0c;通过将单词连接在一起&#xff0c;并使每个单词的首字母大写来表示复合词或短语。这种命名法有小驼峰法和大驼峰法两种变种。 二、小驼峰命名法&…...

Android IME输入法启动显示隐藏流程梳理

阅读Android AOSP 12版本代码&#xff0c;对输入法IME整体框架模块进行学习梳理&#xff0c;内容包含输入法框架三部分IMM、IMMS、IMS的启动流程、点击弹出流程、显示/隐藏流程&#xff0c;以及常见问题和调试技巧。 1. IME整体框架​​​​​​​ IME整体分为三个部分&#xf…...

Java 入门指南:JVM(Java虚拟机)——类的生命周期与加载过程

文章目录 类的生命周期类加载过程1&#xff09;载入&#xff08;Loading&#xff09;2&#xff09;验证&#xff08;Verification&#xff09;文件格式验证符号引用验证 3&#xff09;准备&#xff08;Preparation&#xff09;4&#xff09;解析&#xff08;Resolution&#xf…...

Unity射击游戏开发教程:(36)敌人关卡生成器的设计和开发

丰富多样地游戏关卡生成器能自动生成不同的关卡地图和游戏内容,以增加游戏的可玩性和挑战性。关卡生成可以基于随机算法或者预设的规则生成不同的地图布局、敌人位置、道具位置等。 定义关卡生成器WaveSpawner 如何设置通用的 Wave Spawner?我将此 Wave Spawner 脚本附加到…...

AI对汽车行业的冲击和比亚迪新能源汽车市场占比

人工智能&#xff08;AI&#xff09;对汽车行业的冲击正在迅速改变该行业的面貌&#xff0c;从智能驾驶到生产自动化&#xff0c;再到个性化的消费者体验&#xff0c;AI带来的技术革新在各个层面影响着汽车产业。与此同时&#xff0c;新能源汽车市场&#xff0c;特别是以比亚迪…...

2024年中国电子学会青少年软件编程(Python)等级考试(一级)核心考点速查卡

考前练习&#xff1a; 2024年06月中国电子学会青少年软件编程&#xff08;Python&#xff09;等级考试试卷&#xff08;一级&#xff09;答案 解析-CSDN博客 2024年03月中国电子学会青少年软件编程&#xff08;Python&#xff09;等级考试试卷&#xff08;一级&#xff09;答…...

游戏开发引擎__游戏场景(灯光,摄像机)

1.灯光 重要参数介绍 类型: 控制灯光的类型&#xff0c;有“定向”“点”“区域”和“聚光”4种模式。颜色: 控制灯光的颜色。模式: 控制灯光的光照模式&#xff0c;有“实时”“混合”和“烘焙”3种模式。强度: 控制灯光的明亮程度。间接乘数: 改变间接光的强度。阴影类型: …...

2024 Snap 新款ar眼镜介绍

2024 snap 新款ar眼镜介绍 2024 Snap 新款ar眼镜介绍 咨询合作 DataBall 项目&#xff0c;欢迎加以下微信。 助力快速掌握数据集的信息和使用方式。...

uni-app生命周期

目录 一、页面生命周期 1、onLoad 【常用】 2、onShow【常用】 3、onReady【常用】 4、onHide【常用】 5、onPullDownRefresh【常用】 6、onReachBottom【常用】 二、应用生命周期 1、onLaunch【常用】 2、onShow【常用】 3、onHide【常用】 三、组件生命周期 1、…...

LabVIEW机械产品几何精度质检系统

随着制造业的发展&#xff0c;对产品质量的要求越来越高&#xff0c;机械产品的几何精度成为衡量其品质的重要指标。为了提高检测效率和精度&#xff0c;开发了一套基于LabVIEW的几何精度质检系统&#xff0c;该系统不仅可以自动化地进行几何尺寸的测量&#xff0c;而且能实时分…...

java 检测图片链接有没有效

实际需求&#xff1a;发送调用微信图片发送接口前检验图片有效性。 在 Java 中&#xff0c;检测图片链接是否有效可以通过发送 HTTP 请求来判断服务器返回的状态码。通过 HttpURLConnection 类&#xff0c;可以轻松地实现这个功能。以下是一个简单的示例代码来检测图片链接是否…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...