Java 面试必问的线程池原理总结

news2025/1/16 15:01:57

本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻,欢迎关注"慕课网"!

作者:大能老师 | 慕课网讲师


Java 线程池原理总结

(一)什么是线程池

线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。

他的主要特点为:

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统 的稳定性,使用线程池可以进行统一的分配,调优和监控

(二)线程池的基本原理

线程池的组成一般的线程池主要分为以下 4 个组成部分:

  1. 线程池管理器:用于创建并管理线程池

  2. 工作线程:线程池中的线程

  3. 任务接口:每个任务必须实现的接口,用于工作线程调度其运行

  4. 任务队列:用于存放待处理的任务,提供一种缓冲机制

ThreadPoolExecutor 的构造方法如下:

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

构造函数参数说明:

参数描述
corePoolSize指定了线程池中的线程数量。
maximumPoolSize指定了线程池中的最大线程数量。
keepAliveTime当前线程池数量超过 corePoolSize 时,多余的空闲线程的存活时间,即多次时间内会被销毁。
unitkeepAliveTime 的单位。
workQueue任务队列,被提交但尚未被执行的任务。
threadFactory线程工厂,用于创建线程,一般用默认的即可。
handler拒绝策略,当任务太多来不及处理,如何拒绝任务。

线程池都有哪几种工作队列

1、ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。

2、LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列

3、SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。

4、PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

拒绝策略 :

线程池中的线程已经用完了,无法继续为新任务服务,同时,等待队列也已经排满了,再也塞不下新任务了。这时候我们就需要拒绝策略机制合理的处理这个问题。

JDK 内置的拒绝策略如下:

策略描述
AbortPolicy直接抛出异常,阻止系统正常运行。
CallerRunsPolicy只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。显然这样做不会真的丢弃任务,但是,任务提交线程的性能极有可能会急剧下降。
DiscardOldestPolicy丢弃最老的一个请求,也就是即将被执行的一个任务,并尝试再次提交当前任务。
DiscardPolicy该策略默默地丢弃无法处理的任务,不予任何处理。如果允许任务丢失,这是最好的一种方案。

以上内置拒绝策略均实现了 RejectedExecutionHandler 接口,若以上策略仍无法满足实际需要,完全可以自己扩展 RejectedExecutionHandler 接口。

Java线程池工作过程

  1. 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。

  2. 当调用 execute() 方法添加一个任务时,线程池会做如下判断:

    a) 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;

    b) 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;

    c) 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;

    d) 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常 RejectExecutionException。

  3. 当一个线程完成任务时,它会从队列中取下一个任务来执行。

  4. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

(三) Executor框架

Executor框架同java.util.concurrent.Executor 接口在Java 5中被引入。Executor框架是一个根据一组执行策略调用,调度,执行和控制的异步任务的框架。

无限制的创建线程会引起应用程序内存溢出。所以创建一个线程池是个更好的的解决方案,因为可以限制线程的数量并且可以回收再利用这些线程。利用Executor框架可以非常方便的创建一个线程池。

Executors类是什么?

Executors可以用于方便的创建线程池。

Java 中的线程池是通过 Executor 框架实现的,该框架中用到了 Executor,Executors,ExecutorService,ThreadPoolExecutor ,Callable 和 Future、FutureTask 这几个类。

常见线程池的快捷创建方式

要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在Executors类里面提供了一些静态工厂,生成一些常用的线程池。

newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

newFixedThreadPool

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

newCachedThreadPool

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,

那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

newScheduledThreadPool

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

(四)为什么不建议使用 Executors静态工厂构建线程池

阿里巴巴Java开发手册,明确指出不允许使用Executors静态工厂构建线程池
原因如下:
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险

说明:Executors返回的线程池对象的弊端如下:

  • 1:FixedThreadPool 和 SingleThreadPool:
    允许的请求队列(底层实现是LinkedBlockingQueue)长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM
  • 2:CachedThreadPool 和 ScheduledThreadPool
    允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。

 

欢迎关注「慕课网」帐号,我们会一直坚持内容原创,提供IT圈优质内容,分享干货知识,大家一起共同成长吧!
本文原创发布于慕课网 ,转载请注明出处,谢谢合作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/491266.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Arcgis进阶篇(4)——arcgis js api使用geoserver服务

1、geoserver安装方法 geoserver-2.19.x&#xff08;此版本支持jdk8.x&#xff09;的下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1PkmmjHWWzbUA9fYfa110Ew?pwd8tvf 提取码&#xff1a;8tvf 经测试&#xff0c;最新版本的geoserver需要jdk11&#xff…

elasticsearch 使用的基础工具包及配置安装信息

前言:elasticsearch 工具在查询大量数据上面有明显的优势&#xff0c;但是具体的使用门槛相对较高&#xff0c;具体使用中不同版本使用上还有些差别&#xff0c;需要匹配上 spring boot elasticsearch 版本才能少出错 使用到的工具包&#xff0c;注意具体的版本 elasticsearc…

坚持伙伴优先,共创数据存储新生态

4 月 26 日&#xff0c;2023 阿里云合作伙伴大会上&#xff0c;阿里巴巴集团董事会主席兼 CEO、阿里云智能集团 CEO 张勇表示&#xff0c;阿里云的核心定位是一家云计算产品公司&#xff0c;生态是阿里云的根基。让被集成说到做到的核心&#xff0c;是要坚定走向“产品被集成”…

linux0.12-8-4-sys_call.s

[301页] 8-4 sys_call.s 程序 sys_call.s 程序简单总结&#xff1a; int 0x80 – _system_call int16 – 处理器错误中断 int7 – 设备不存在或协处理器不存在。 int32 – (int 0x20)时钟中断处理程序。 两个系统功能的底层接口&#xff0c;分别是 sys_execve 和 sys_fork 。…

​Prometheus集群编队开发套件升级上市

Prometheus集群编队开发套件是一个面向集群、多智能体相关研究方向的无人机二次开发平台&#xff0c;采用分布式集群算法。与传统无人机集群相比&#xff0c;分布式无人机集群更加灵活、可靠和高效&#xff0c;可应用于更加复杂及多样化的任务场景。 分布式集群科研平台&#x…

Linux 内存管理 pt.2

哈喽大家好我是咸鱼&#xff0c;在《Linux 内存管理 pt.1》中我们学习了什么是物理内存、虚拟内存&#xff0c;了解了内存映射、缺页异常等内容 那么今天我们来接着学习 Linux 内存管理中的多级页表和大页 多级页表&大页 在《Linux 内存管理 pt.1》中我们知道了内核为每…

【Vue】学习笔记-Vue CLI ref props mixin plugin scoped

ref 属性 ref被用来给元素或子组件注册引用信息(id的代替者) 应用在html标签上获取的真实的DOM元素&#xff0c;应用在组件标签上获取的组件实列对象vc使用方式 a. 打标识:或 b.获取&#xff1a;this.$refs.xxx <template><div><h1 v-text"msg" re…

MySQL 优化一MySQL优化步骤

目录 定位执行效率较低的 SQL 1&#xff09;慢查询 2&#xff09;processlist 定位执行效率较低的 SQL 定位执行效率比较慢的 SQL 语句&#xff0c;一般有三种方式 1、可以通过慢查询日志来定位哪些执行效率较低的 SQL 语句。 2、使用 show processlist 命令查看当前 MyS…

紧急下架,AI以假乱真学明星唱歌;哈佛法学院专家谈AI和版权法

几周前&#xff0c;一首据称由 Drake 和 The Weeknd 创作的新歌登陆 TikTok 和 Spotify&#xff0c;并迅速在互联网上像野火一样传播开来。“我袖子上的心”在嘻哈乐迷中获得了好评如潮和高度兴奋&#xff0c;这不仅是因为该曲目具有感染力的歌词和旋律&#xff0c;而且还因为对…

【云原生】云原生服务网格流量控制思考

文章目录 前言一、什么是流量控制&#xff1f;二、存在三种场景三、场景分析 前言 随着云原生技术的不断发展及应用&#xff0c;很多服务都已部署上云。 保障云上环境的稳定是重要的一环。 一个重要的影响稳定的场景就是突发大流量冲击。 面对该场景&#xff0c;较好的应对…

C#asp.net core学生信息管理系统

C#asp.net core学生信息管理系统 运行前附加数据库.mdf&#xff08;或sql生成数据库&#xff09; 主要技术&#xff1a; 基于asp.net core架构和sql server数据库 功能模块&#xff1a; 首页登陆&#xff0c;分别为管理员&#xff08;学生管理 用户角色管理 授课信息管理&…

Linux_红帽8学习笔记分享_8(文件系统管理FS Management)

Linux_红帽8学习笔记分享_8&#xff08;文件系统管理FS Management&#xff09; 文章目录 Linux_红帽8学习笔记分享_8&#xff08;文件系统管理FS Management&#xff09;1.操作系统的两种启动模式: Legacy BIOS和UEFI1.1 Legacy BIOS1.2 UEFI 2.磁盘分区表的两种类型: MBR和GP…

【图像分割】【深度学习】SAM官方Pytorch代码-Mask decoder模块MaskDeco网络解析

【图像分割】【深度学习】SAM官方Pytorch代码-Mask decoder模块MaskDeco网络解析 Segment Anything&#xff1a;建立了迄今为止最大的分割数据集&#xff0c;在1100万张图像上有超过1亿个掩码&#xff0c;模型的设计和训练是灵活的&#xff0c;其重要的特点是Zero-shot(零样本迁…

ASP.NET动态Web开发技术第8章

第8章ASP.NET数据访问 一.预习笔记 1.SqlDataSource控件 SqlDataSource数据源控件支持连接SQL关系数据库&#xff0c;它使用SQL命令来检索和修改数据。通常将SqlDataSource数据源控件与数据绑定控件一起使用。 属性1&#xff1a;ID&#xff1a;当前数据源控件的唯一标识符 …

maven从入门到精通 第三章 Maven中形成web对Java工程的依赖

这里写自定义目录标题 一 war永远依赖于jar1. 在web工程的项目2中,加入项目1的路径依赖2 在web工程中&#xff0c;加入测试代码2.1 创建目录2.2 确认依赖junit2.3创建测试类2.4 运行测试2.5 打包2.6 查看依赖列表2.7 树形结构查看 二 测试依赖的范围1 compile的编译过程1.1 com…

如何安全免费地备份VMware虚拟机?

在没有备份的情况下在虚拟机上运行所有工作负载是有风险的。任何人为错误或自然灾害都可能对您的 VMware 虚拟机造成不可逆转的损坏&#xff0c;您无法预测下一秒您的虚拟机会发生什么。因此&#xff0c;您需要一个可靠的免费 vmware 备份解决方案来保护您的虚拟机数据免受安全…

Ubuntu 23.04 安装 Jupyter

Ubuntu 23.04 安装 Jupyter 1. 安装 Python 和 pip2. 升级 pip 至最新版本3. 安装 Jupyter4. 测试是否安装成功5. (可选)安装 Jupyter 内核和扩展6. (可选)配置 Jupyter&#xff0c;设置密码等 1. 安装 Python 和 pip sudo apt install -y python3 python3-pip2. 升级 pip 至最…

ASEMI代理ADP5054ACPZ-R7原装ADI车规级ADP5054ACPZ-R7

编辑&#xff1a;ll ASEMI代理ADP5054ACPZ-R7原装ADI车规级ADP5054ACPZ-R7 型号&#xff1a;ADP5054ACPZ-R7 品牌&#xff1a;ADI/亚德诺 封装&#xff1a;LFCSP-48 批号&#xff1a;2023 引脚数量&#xff1a;48 工作温度&#xff1a;-40C~125C 安装类型&#xff1a;表…

[2023-DAS x SU战队2023开局之战] crypto-sign1n

题目描述&#xff1a; from secret import r, t from Crypto.Util.number import *flag bxxx flag bytes_to_long(flag) e 0x10001def gen_keys():p getPrime(1024)q getPrime(1024)phi (p-1)*(q-1)d inverse(e,phi)n p*qprint(fn {n})WHATF (d ** 3 3) % phiprint…

Python模块篇:函数/类/变量和常量/注释/导入和使用

大家好&#xff0c;我是辣条哥&#xff01;本期应邀写了一些Python模块相关内容~ Python模块是一种组织Python代码的方式&#xff0c;它将相关的代码放在一个文件中&#xff0c;以便于重用和维护。Python模块可以包含函数、类、变量和常量等&#xff0c;可以被其他Python程序导…