线程进阶-1 线程池
一.说一下线程池的执行原理
1.线程池的七大核心参数
(1)int corePoolSize:核心线程数。默认情况下核心线程会一直存活,当设置allowCoreThreadTimeout为true时,核心线程也会被超时回收。
(2)int maximumPoolSize:线程池能容纳的最大线程数。maximumPoolSize = 核心线程数 + 救急线程数。
(3)long keepAliveTime:线程闲置的超时时长。当线程闲置超时时,此线程会被回收,释放资源。超时回收默认情况下只针对救急线程。
(4)TimeUnit unit:keepAliveTime的时间单位,如TimeUnit.MILLISECONDS、TimeUnit.SECONDS等。
(5)BlockingQueue<Runnable> workQueue:任务队列。当核心线程数都被占用时,新提交的任务会被放到任务队列中等待。
(6)ThreadFactory threadFactory:线程工厂,为可选参数。
a.ThreadFactory为一个接口,只提供一个newThread()方法,传入一个Runnable对象,返回一个执行该Runnable的Thread对象。用于定制线程对象的创建。
b.若未指定ThreadFactory,则线程池会使用默认的ThreadFactory——只是创建Thread执行Runnable,不对线程作额外的处理。
(7)RejectedExecutionHandler handler:拒绝策略,为可选参数
a.当核心线程、救急线程都被占用,且任务队列已满时,会对新提交的任务执行拒绝策略。
b.若未指定拒绝策略,则线程池会默认使用AbortPolicy
2.线程池的拒绝策略
(1)AbortPolicy:丢弃新任务,并抛出异常。
(2)DiscardPolicy:丢弃新任务,但不会抛出异常。
(3)DiscardOldestPolicy:丢弃任务队列队头的任务,将新任务插入到任务队列队尾。
(4)CallerRunsPolicy:让调用者线程自己来执行任务。即如果当前线程A向线程池提交了一个任务,且该任务触发了线程池的CallerRunsPolicy拒绝策略,则线程池会将该任务退回给线程A,让线程A来执行该任务。
(5)自定义拒绝策略:实现RejectedExecutionHandler接口,并重写rejectedExecution()方法。
3.线程池的执行原理
对于新提交的任务:
(1)判断核心线程是否有空闲,若有空闲则交由核心线程执行。若核心线程都被占用,则继续判断
(2)判断等待队列是否有空位,若有空位则插入到队尾。若等待队列已满,则继续判断
(3)判断救急线程是否有空闲,若有空闲则交由救急线程执行。若救急线程都被占用,则执行拒绝策略
补充:
(1)核心线程和救急线程每执行完一个任务,都会再去等待队列中取待执行任务继续执行。若等待队列中没有任务,则默认情况下,核心线程进入空闲状态,救急线程开始闲置超时的计时。
(2)当核心线程都被占用且等待队列已满时,才会创建救急线程来执行新任务。被创建的救急线程,会直接忽视等待队列的任务,先去执行新提交的任务;等到新任务执行完,才会开始执行等待队列的任务。
二.线程池中常见的任务队列
1.ArrayBlockingQueue:基于数组结构的有界阻塞队列,任务执行顺序为FIFO
2.LinkedBlockingQueue:基于链表结构的有界阻塞队列,任务执行顺序为FIFO
3.DelayedWorkQueue:是一个优先级队列。在提交任务时可以指定当前任务需要延时多长时间后才执行,DelayedWorkQueue的任务执行顺序为当前队列中指定执行时间最早的任务。
4.SynchronousQueue:不存储元素的阻塞队列。每个线程的插入操作都需要等待另一个线程的移除操作,是线程和线程间的传递。
三.说一下ArrayBlockingQueue和LinkedBlockingQueue的区别
1.底层数据结构
(1)ArrayBlockingQueue底层是数组
(2)LinkedBlockingQueue底层是单向链表
2.容量
(1)ArrayBlockingQueue是强制有界,创建时需要传入一个int值作为容量
(2)LinkedBlockingQueue是默认无界,支持有界。默认容量为Integer.MAX_VALUE,创建时可以传入一个int值作为容量。
3.加锁方式
ArrayBlockingQueue和LinkedBlockingQueue都是使用ReentrantLock加锁。
(1)ArrayBlockingQueue的插入和删除操作都是只加一把锁,同时锁住入队和出队。
(2)LinkedBlockingQueue插入操作锁尾节点,不锁头节点;删除操作锁头节点,不锁尾节点。即在执行入队时可以出队,执行出队时可以入队,效率更高。
四.线程池的execute()和submit()方法的区别
线程池可以通过execute()或submit()方法来提交任务
1.执行对象不同
(1)execute(Runnable command):该方法用于执行Runnable接口的任务
(2)submit(Callable<T> task)、submit(Runnable task)、submit(Runnable task,T result):submit()的三个重载方法表明其既可以执行Callable接口任务也可以执行Runnable接口任务。传入的Runnable接口在内部会先被转化为Callable接口再作为任务执行,因此submit()方法最终的执行对象都是Callable接口。
2.返回值不同
(1)execute()方法执行对象是Runnable接口任务,Runnable的run()方法没有返回值,因此execute()方法也没有返回值。execute()主要用于执行不需要返回结果的任务。
(2)submit()方法最终执行对象都是Callable接口任务,其返回值为Future<T>,可以调用Future的get()方法获取任务执行后的返回值。
3.异常处理不同
(1)execute()提交的任务在执行中遇到异常时,会将异常传递给线程的UncaughtExceptionHandler处理,默认是直接将异常抛出。
(2)submit()提交的任务在执行中遇到异常时,仅仅是停止执行任务,但不会将异常立即抛出,相当于暂时吞掉异常;直到外部调用Future的get()方法尝试获取任务执行的返回值时,才会将异常抛出。即允许延迟处理异常。
五.线程池有哪几种状态?
1.RUNNING:线程池的初态,代表线程池正在处理和接收任务。
2.SHUTDOWN:调用shutdown()方法会进入此状态。表明线程池不再接收新任务,但会继续处理已经提交到等待队列的任务。
3.STOP:调用shutdownNow()方法会进入此状态。表明线程池不再接收新任务,也不会再处理等待队列中的任务,同时还会尝试中断正在执行的任务。
4.TIDYING:过渡态,当线程池的所有任务都已经终止(无论是正常执行完还是通过取消或异常终止),并且所有工作线程都关闭,就会进入此状态。该状态下,线程池会执行terminated()钩子方法。
5.TERMINATED:最终态。当terminated()方法执行完就会进入此状态,代表线程池完全终止。
六.线程池的种类有哪些?
Executors类提供了创建多种线程池的静态方法,常见的有4种:
1.newFixedThreadPool:固定线程数的线程池。
(1)核心线程数=最大线程数,无救急线程。
(2)任务队列为LinkedBlockingQueue,容量为默认的Integer.MAX_VALUE。
(3)适用于任务量已知,相对耗时的任务。
2.newSingleThreadPool:单线程化的线程池。
(1)核心线程数=最大线程数=1,作为唯一的工作线程;无救急线程。
(2)任务队列为LinkedBlockingQueue,容量为默认的Integer.MAX_VALUE。
(3)适用于按照顺序执行的任务。
3.newCachedThreadPool:可缓存线程
(1)核心线程数=0,最大线程数=救急线程数=Integer.MAX_VALUE,即全为救急线程在工作,因此可以灵活创建、回收线程。
(2)任务队列为SynchronousQueue
(3)适用于任务数比较密集,但每个任务执行时间较短的情况。
4.newScheduledThreadPoolExecutor:具有延迟和周期执行功能的线程池。
(1)核心线程数自定义,最大线程数=Integer.MAX_VALUE。
(2)任务队列为DelayedWorkQueue,使用schedule()提交任务,指定任务的延时执行时间。
七.为什么不建议使用Executors类提供的方法创建线程?
1.FixedThreadPool和SignalThreadPool都允许任务队列的长度为Integer.MAX_VALUE,可能会堆积大量的任务请求,导致OOM。
2.newCachedThreadPool和newScheduledThreadPool的最大线程数都为Integer.MAX_VALUE,可能会创建大量的线程,导致OOM。
八.如何控制某个方法允许并发访问线程的数量?
1.使用newFixedThreadPool,但有OOM的风险。
2.使用Semaphore类,每一个线程访问该方法都acquire()获取一个信号量,若信号量数大于0,则该线程获取到一个信号量,信号量数减1;若信号量数小于0,则该线程阻塞;若线程执行完该方法,则release()释放一个信号量,信号量数加1。
九.如何确定线程池的核心线程数?
假设cpu的核数为N
1.对于高并发、执行时间短的任务:需要减少线程数以减少线程上下文切换带来的消耗。因此核心线程数设置为N+1。
2.对于并发不高、任务执行时间长的任务:
(1)IO密集型任务:例如文件读写、DB读写、网络请求等,不需要占用过多cpu。核心线程数设置为2N+1。
(2)cpu密集型任务:例如计算型代码、Bitmap转换、Gson转换等,需大量占用cpu,需要减少线程数以减少线程上下文切换带来的消耗。因此核心线程数设置为N+1。
十.说一下线程池的使用场景
1.数据批量导出
(1)使用线程池+CountDownLatch批量将数据库中的数据导出,避免OOM。
(2)场景:例如使用分页查询去导出数据库中的数据,线程池的每个线程负责一页数据的导出,并发执行,每有一个线程执行完,CountDownLatch减一,直到所有线程执行完,CountDownLatch等于零,主线程才继续执行。
2.数据汇总
(1)如果一个请求要调用多个接口来汇总数据,且接口间没有依赖关系,则可以使用线程池+Future获取调用结果的方式来并发执行,提升性能。
3.异步线程
(1)为了避免下一级方法影响上一级方法响应时间,可以使用异步线程并发调用下一级方法(前提是不需要下一级方法的返回值),提高响应速率。
相关文章:

线程进阶-1 线程池
一.说一下线程池的执行原理 1.线程池的七大核心参数 (1)int corePoolSize:核心线程数。默认情况下核心线程会一直存活,当设置allowCoreThreadTimeout为true时,核心线程也会被超时回收。 (2)i…...

LabVIEW中PID控制器系统的噪声与扰动抑制策略
在LabVIEW中处理PID控制器系统中的噪声和外部扰动,需要从信号处理、控制算法优化、硬件滤波和系统设计四个角度入手。采用滤波技术、调节PID参数、增加前馈控制和实施硬件滤波器等方法,可以有效减少噪声和扰动对系统性能的影响,提高控制系统的…...

JavaWeb笔记整理+图解——Listener监听器
欢迎大家来到这一篇章——Listener监听器 监听器和过滤器都是JavaWeb服务器三大组件(Servlet、监听器、过滤器)之一,他们对于Web开发起到了不可缺少的作用。 ps:想要补充Java知识的同学们可以移步我已经完结的JavaSE笔记&#x…...

AIGC智能办公实战 课程,祝你事业新高度
在数字化时代,人工智能(AI)已经渗透到我们生活的方方面面,从智能家居到自动驾驶,从医疗诊断到金融分析,AI助手正在改变我们的工作方式和生活质量。那么,你是否想过自己也能从零开始,…...

专科生听劝 这种情况你就不要专转本了
罗翔老师说过,读书学习主要作用是提高人的下限 我们能掌握的只有学习,以确保学历不会太差再去等机遇让自己活得更好 大部分情况来说,专科生努力去专转本挺好的提升自己准没错,我当年也是一心这样想的,但今天不得不说点…...

MySQL增删查改初阶
目录 一,数据库操作 1.关键字 show 显示当前数据库有哪些:show databases; 2.创建数据库 3.选中数据库 4.删除数据库 二,表的操作,在选中数据库的基础之上 1.查看表的结构 2.创建表 3.查看当前选中的数据库中…...

IService 接口中定义的常用方法
文心一言生成 以下是一些 IService 接口中定义的常用方法(以你提供的 UserSQL 类为例,该类继承自 ServiceImpl,因此也会拥有这些方法): 插入(新增) boolean save(T entity): 插入一条记录&…...

api网关kong对高频的慢接口进行熔断
一、背景 在生产环境,后端服务的接口响应非常慢,是因为数据库未创建索引导致。 如果QPS低的时候,因为后端服务有6个高配置的节点,虽然接口慢,还未影响到服务的正常运行。 但是,当QPS很高的时候,…...

python作业:实现一个任务列表管理系统,使用到python类、对象、循环等知识
实现一个简单的任务列表管理系统,可以用于python学习的作业或者练习。系统的功能包括: 用户可以添加任务、查看任务列表、标记任务为已完成,以及删除任务。 代码如下: class Task: def __init__(self, name, completedFalse):…...

大宋咨询(深圳产品价格调查)如何开展电子商品渠道价格监测
开展电子商品渠道价格监测是当今电商时代的重要任务之一。随着电子商务的迅猛发展,电子商品的价格波动日益频繁,市场竞争也愈发激烈。为了解优化渠道管理策略,提升品牌竞争力,大宋咨询(深圳市场调查)受客户…...

py黑帽子学习笔记_web攻击
python网络库 py2的urllib2 py3好像把urllib2继承到了标准库urllib,直接用urllib就行,urllib2在urllib里都有对应的接口 py3的urllib get请求 post请求,和get不同的是,先把post请求数据和请求封装到request对象,再…...

MVC、MVP 和 MVVM 架构总结
MVC、MVP 和 MVVM 是常见的软件架构模式,主要用于组织应用程序的结构,特别是在用户界面和业务逻辑之间进行分离。以下是对它们的详细解释,包括它们的差异、优缺点。 MVC(Model-View-Controller) 结构 Model…...

C++ vector的使用和简单模拟实现(超级详细!!!)
目录 前言 1.STL是什么 2.vector使用 2.1 vector简介 2.2 常用接口函数 1. 构造函数 2.operator[ ]和size,push_back 3. 用迭代器进行访问和修改 4. 范围for遍历 5.修改类型函数 pop_back find insert erase 6. 容量相关函数capacity resize reserve 3.…...

MySQL中,不能在一个DML(数据操纵语言,如INSERT, UPDATE, DELETE)语句中直接引用目标表进行子查询
错误示例 <delete id"deleteOldRelations">DELETE FROM departments_closure_tableWHERE descendant IN ( SELECT descendant FROM departments_closure_tableWHERE ancestor #{departmentId})</delete>程序运行之后,会报错:You …...

【CH32V305FBP6】4. systick 配置
配置 main.c void SYSTICK_Init_Config(u_int64_t ticks) {SysTick->SR & ~(1 << 0);//clear State flagSysTick->CMP ticks - 1;SysTick->CNT 0;SysTick->CTLR 0xF;NVIC_SetPriority(SysTicK_IRQn, 15);NVIC_EnableIRQ(SysTicK_IRQn); }中断计数 …...

【PECL】在扩展中实现 autoload
【PECL】在扩展中实现 autoload 摘要PHP代码想这么写C 代码这么实现 摘要 php-8.3.x 用扩展写个框架。想实现类管理器,自动加载,上代码: PHP代码想这么写 $ws new \Ziima\Applet(); $ws->import(Ziima, ../base/core); $ws->runAu…...

企业微信H5授权登录
在企业中如果需要在打开的网页里面携带用户的身份信息,第一步需要获取code参数 如何实现企业微信H5获取当前用户信息即accessToken? 1.在应用管理--》创建应用 2.创建好应用,点击应用主页-》设置-》网页-》将授权链接填上去 官方文档可以看…...

玩机进阶教程------修改gpt.bin分区表地址段 完全屏蔽系统更新 fast刷写分区表 操作步骤解析【二】
上期博文简单说明了分区表的基本常识。我们在有些环境中需要屏蔽手机的系统更新选项。除了以前博文中说明的修改系统更新下载文件夹的方法。还可以通过修改分区表类达到目的。在一些辅助维修工具上面带修改分区表功能。修改后效果为屏蔽系统更新和可以恢复出厂。原则上不深刷都…...

Java实现数据结构---数组
文章目录 概念存储原理数组的操作完整代码 概念 数组是(Array)是有限个相同类型的变量所组成的有序集合,数组中的每一个变量为称为元素。数组是最简单、最常用的数据结构。 数组下标从零开始。 存储原理 数组用一组连续的内存空间来存储一…...

java解析excel文件,返回json
我这里用的是springboot项目,配合Maven使用的。首先需要引入依赖: <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency><dependency…...

uniapp 添加字体ttf
效果图如下 一、逻辑概述 在uniapp中使用字体,一共分成两种情况,一种是普通vue页面,一种是nvue页面引入字体。。 1.vue页面引入字体需要如下步骤 1. 先选择下载一种字体:字体格式一般为 ttf后缀名 黄凯桦律师手写体免费下载和在线…...

Linux入门攻坚——24、BIND编译安装、Telnet和OpenSSH
BIND编译安装 对于没有rpm包,需要源代码编译安装。 1、下载源代码:bind-9.12.2-P1.tar.gz,解压:tar -xf bind-9.12.2-P1.tar.gz 2、完善环境: 1)增加用户组named:groupadd -g 53 named 2&…...

1.5.3 基于Java配置方式使用Spring MVC
本实战教程主要介绍了如何使用Java配置方式来使用Spring MVC框架。相较于XML配置方式,Java配置方式提供了一种更为简洁和灵活的配置方法。 项目创建与配置 创建一个Jakarta EE项目,并设置项目名称和位置。选择Jakarta EE 10版本,不添加依赖&a…...

Artifactory清理二进制文件丢失的制品
一、摘要 当制品上传到 Artifactory 时,Artifactory 会在数据库中记录制品的相关元数据信息,包括文件路径、大小、校验和(如 MD5、SHA1)、上传时间、索引、依赖等。实际的制品二进制文件会存储在指定的存储后端,具体的…...

C#中的数组探索
在C#编程语言中,数组是一种基本的数据结构,用于存储固定大小的同类型元素序列。本文将深入探讨C#数组的各个方面,包括定义、赋值、范围操作、切片、多维数组(矩形与锯齿形)、简化初始化表达式以及边界检查。 数组定义…...

身份认证与口令攻击
身份认证与口令攻击 身份认证身份认证的五种方式口令认证静态口令动态口令(一次性口令)动态口令分类 密码学认证一次性口令认证S/KEY协议改进的S/KEY协议 其于共享密钥的认证 口令行为规律和口令猜测口令规律口令猜测 口令破解操作系统口令破解Windows密码存储机制Windows密码破…...

卷积网络迁移学习:实现思想与TensorFlow实践
摘要:迁移学习是一种利用已有知识来改善新任务学习性能的方法。 在深度学习中,迁移学习通过迁移卷积网络(CNN)的预训练权重,实现了在新领域或任务上的高效学习。 下面我将详细介绍迁移学习的概念、实现思想,…...

Ansible04-Ansible Vars变量详解
目录 写在前面6 Ansible Vars 变量6.1 playbook中的变量6.1.1 playbook中定义变量的格式6.1.2 举例6.1.3 小tip 6.2 共有变量6.2.1 变量文件6.2.1.1 变量文件编写6.2.1.2 playbook编写6.2.1.3 运行测试 6.2.2 根据主机组使用变量6.2.2.1 groups_vars编写6.2.2.2 playbook编写6.…...

Flutter 中的 SliverCrossAxisGroup 小部件:全面指南
Flutter 中的 SliverCrossAxisGroup 小部件:全面指南 Flutter 是一个功能丰富的 UI 开发框架,它允许开发者使用 Dart 语言来构建高性能、美观的移动、Web 和桌面应用。在 Flutter 的丰富组件库中,SliverCrossAxisGroup 是一个较少被使用的组…...

开源还是闭源这是一个问题
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...