当前位置: 首页 > 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;可以轻松地实现这个功能。以下是一个简单的示例代码来检测图片链接是否…...

测试工程师学历路径:从功能测试到测试开发

现在软件从业者越来越多&#xff0c;测试工程师的职位也几近饱和&#xff0c;想要获得竞争力还是要保持持续学习。基本学习路径可以从功能测试-自动化测试-测试开发工程师的路子来走。 功能测试工程师&#xff1a; 1、软件测试基本概念&#xff1a; 学习软件测试的定义、目的…...

JavaEE---Spring IOC(2)

DI之三种注入 属性注入 构造方法注入 Setter注入 当程序中同一个类有多个对象的时候会报错解决方法如下: AutoWired和Resource的区别...

Oracle字符集

select userenv(language) from dual;如果显示如下&#xff0c;一个汉字占用两个字节 SIMPLIFIED CHINESE_CHINA.ZHS16GBK如果显示如下&#xff0c;一个汉字占用三个字节 SIMPLIFIED CHINESE_CHINA.AL32UTF8可以用以下语句查询一个汉字占用的字节长度 select lengthb(你) fr…...

RabbitMQ 常见使用模式详解

RabbitMQ 常见使用模式详解 RabbitMQ 是一个强大的消息队列中间件&#xff0c;支持多种消息通信模式&#xff0c;能够适应不同的业务场景。在这篇文章中&#xff0c;我们将详细介绍 RabbitMQ 的几种常见使用方法及其对应的场景。 1. 发布/订阅&#xff08;Publish/Subscribe&a…...

JavaEE初阶——初识EE(Java诞生背景,CPU详解)

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c;你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能帮到你&#xff01; 目录 零&#xff1a;Java的发展背景介绍 一&#xff1a;EE的概念 二&#xff1a;计算机的构成 1&#xff1a;CU…...

iOS界面布局:屏幕尺寸与安全区域全面指南

引言 随着iPhone和iPad的更新迭代&#xff0c;iOS设备的屏幕尺寸和设计也在不断变化。无论是iPhone X系列的刘海屏&#xff0c;还是最新的iPhone 14&#xff0c;开发者都需要面对适配不同设备布局的问题。在项目开发中&#xff0c;导航栏、状态栏、TabBar的高度以及安全区域的…...

javascript-代码执行原理

js 是解释型语言 js 引擎执行流程 分为两个阶段: 语法分析执行阶段执行阶段涉及的数据结构: 调用栈。处理执行上下文和执行代码内存堆。给对象分配内存任务队列。暂存待执行的任务,分为宏任务队列和微任务队列语法分析 词法分析 > 语法分析 > 代码生成(字节码) …...

【C++ | tips】const Date* operator() const中这两个const有什么区别?他们的作用是什么?

const Date* operator&() const { return this; } 我们要明白operator&()这个函数是做什么的。 在C中&#xff0c;&操作符通常用于获取一个对象的地址。但是&#xff0c;有时候我们想要自定义这个行为&#xff0c;比如说&#xff0c;我们想要控制别人怎么获取…...

开放的数据时代:Web3和个人隐私的未来

在数字化和信息化的时代&#xff0c;数据隐私成为了公众关注的焦点。随着Web3技术的兴起&#xff0c;个人隐私保护进入了一个新的阶段。Web3作为去中心化的互联网架构&#xff0c;提出了对数据控制和隐私保护的新方案。本文将探讨Web3如何影响个人隐私的未来&#xff0c;并分析…...

Kafka 安全机制详解及配置指南

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…...