【并发编程-3】线程池

对于多线程来说,new Thread一定是创建了线程,而Runnable只是一个任务,并没有创建新的线程。  所以,Runnable任务要交给线程来执行。 如果对于每个任务都创建一个线程来执行,显然是不合理的。
线程池就是为了复用线程来处理多个任务,像tomcat, dubbo,数据库连接池等常用的框架都会使用线程池。 在自己开发的过程中,也可能会使用多线程的情况。 比如,一个请求的步骤太多,可以使用多线程并行执行。

线程池继承关系:

 看两个核心类:ThreadPoolExecutor 和 ScheduledThreadPoolExecutor

ThreadPoolExecutor:

基本介绍:

//...private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 存放任务的阻塞队列
private final BlockingQueue<Runnable> workQueue;
// 对线程池内部各种变量进行互斥访问控制
private final ReentrantLock mainLock = new ReentrantLock();
// 线程集合
private final HashSet<Worker> workers = new HashSet<Worker>();
线程池中的每一个线程就是一个 Worker 对象:
private final class Worker extends AbstractQueuedSynchronizer implements
Runnable {
// ...
final Thread thread; // Worker封装的线程
Runnable firstTask; // Worker接收到的第1个任务
volatile long completedTasks; // Worker执行完毕的任务个数
// ...
}
由定义会发现, Worker 继承于 AQS ,也就是说 Worker本身就是一把锁,锁的就是worker对象本身。 lock 方法一旦获取了独占锁,表示当前线程正在执行任务中,那么它会有以下几个作用:
  1. 如果正在执行任务,则不应该中断线程;
  2. 如果该线程现在不是独占锁的状态,也就是空闲的状态,说明它没有在处理任务,这时可以对该线程进行中断;
  3. 线程池在执行 shutdown 方法或 tryTerminate 方法时,会调用 interruptIdleWorkers 方法来中断空闲的线程,interruptIdleWorkers 中会使用 tryLock 方法来判断线程池中的线程是否是空闲状态。  说简单点,就是不能直接中断在任务中的线程,做到优雅的关闭。

核心参数: 

    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), handler);}
  1. corePoolSize:在线程池中始终维护的线程个数。
  2. maxPoolSize:在corePooSize已满、队列也满的情况下,扩充线程至此值。
  3. keepAliveTime/TimeUnitmaxPoolSize 中的空闲线程存活时间,销毁后线程数缩回corePoolSize
  4. blockingQueue:线程池所用的队列类型。
  5. threadFactory:线程创建工厂,可以自定义,有默认值:Executors.defaultThreadFactory() 
  6. RejectedExecutionHandlercorePoolSize已满,队列已满,maxPoolSize 已满,最后的拒绝策略。
优雅关闭线程池:
当关闭一个线程池的时候,有的线程还正在执行某个任务,有的调用者正在向线程池提交任务,并且队列中可能还有未执行的任务。因此,关闭过程需要一个平滑的过渡,这就涉及线程池的完整生命周期管理。
线程池状态:
线程池五种状态: RUNNING SHUTDOWN STOP TIDYING TERMINATED 。 关闭时,状态值只能从小到大迁移:
在调用 shutdown() 或者 shutdownNow() 之后,线程池并不会立即关闭,接下来需要调用 awaitTermination() 来等待线程池关闭。

awaitTermination中就是不断循环,每隔500ms去校验一下线程池状态是否为TERMINATED,如果是,则返回。 该状态就是上面说的,worker释放锁后就会更新状态。 

另外,shutdown()只会中断空闲的线程,shutdownNow()会中断所有线程,包括清空任务队列。 

 线程池执行过程:

  1. 执行execute方法向池中提交任务,如果核心线程数小于corePoolSize,即使池中还有其他空闲线程,也会创建新线程执行任务。
  2. 当达到corePoolSize,会放到队列中,空闲线程会从队列中取任务执行,在worker中其实就不断循环的过程。
  3. 队列已满,则会创建新线程,直到数量达到maxPoolSize,则会执行拒绝策略。
  4. 空闲时间超过keepAliveTime的线程,会被销毁,直到数量收缩到corePoolSize。 当然,如果线程池设置了allowCoreThreadTimeOut,只要空闲时间超过的线程都会被销毁。

线程池拒绝策略:

在线程池的execute方法的最后,也就是不满足执行条件时,就会执行拒绝策略。 创建线程池默认的handler是RejectedExecutionHandler =  new AbortPolicy()。

其实线程池提供了4种:

  • AbortPolicy:直接抛异常
  • CallerRunsPolicy:直接调用线程任务的run方法执行,线程池不参与(虽然线程池不再接收,但是线程任务可以自己执行)。
  • DiscardPolicy:直接丢弃任务,也不报错也不干啥,神不知鬼不觉
  • DiscardOldestPolicy:将队列中最早的一条丢弃,再将当前任务添加到队列中。
    • ​​​​​​​

线程池的队列:

ArrayBlockingQueue

        ArrayBlockingQueue(有界队列)是一个用数组实现的有界阻塞队列,按FIFO排序量。

LinkedBlockingQueue

        LinkedBlockingQueue(可设置容量队列)基于链表结构的阻塞队列,按FIFO排序任务,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,可以一直添加,直到资源耗尽。

DelayQueue

        DelayQueue(延迟队列)是一个定时的延迟执行的队列。

SynchronousQueue

SynchronousQueue(直接提交队列),这种队列中不会保存任务,而是直接提交任务给线程处理。如果当前没有线程可用,则新建一个线程处理任务。

Executors: 

concurrent 包提供了 Executors 工具类,利用它可以创建各种不同类型的线程池。
单线程的线程池:

固定线程数的线程池: 

上面两种都是固定了线程数的,所以核心线程数和最大线程数一样多,因此,使用的队列是无边界的LinkedBlockingQueue,理论上可以一直放任务进去。

每接收一个任务就创建线程来执行,不往队列存放:

单线程具有周期调度功能的线程池: 

多线程具有周期调度功能的线程池:

通过以上多种场景下使用的线程池可以发现,各种线程池,无非就是使用不同的参数而已。  Executors还支持传其他参数的线程池,当然,也可以自己定义。

在《阿里巴巴 Java 开发手册》中,其实是明确禁止使用 Executors 创建线程池,并要求开发者自己使用 ThreadPoolExector或 ScheduledThreadPoolExecutor进行创建。这样做是为了强制开发者自己传参,明确线程池的运行策略,使其对线程池的每个配置参数皆做到心中有数,以规避因使用不当而造成资源耗尽的风险。 下面,具体说一下ScheduledThreadPoolExecutor:
ScheduledThreadPoolExecutor:
ScheduledThreadPoolExecutor也是ThreadPoolExector的子类,核心参数都一样,只是做了增强:
延迟执行任务:

有两个方法,可以是Runnable或Callable任务。 在经过delay的时间后,才执行任务。

 

周期性执行任务:

两个方法:

        scheduleAtFixedRate:按固定时间间隔执行,与任务本身的时间没有关系。 比如每隔5s执行一次当前任务。 但是它要求任务本身的执行时间要小于间隔时间,否则下一次开始的时候,上一次还没执行完。

        scheduleWithFixedDelay: 也是按固定的时间间隔执行,但是与任务本身的时间有关系。 比如间隔2s执行一次,任务本身的执行时间是10s,那么下一次执行时间就是12s的时候。

  • initialDelay:说系统启动后,需要等待多久才开始执行第一次。
  • period:间隔执行时间。

延迟执行任务依靠的是 DelayQueue BlockingQueue的一种,其实现原理是二叉堆。当然这里没有直接使用,而是自己实现了一个DelayedWorkQueue。
而周期性执行任务是执行完一个任务之后,再把该任务扔回到任务队列中,如此就可以对一个任务
反复执行。
​​​​​​​

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

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

相关文章

京东按关键词搜索商品列表接口:竞品分析,商品管理,营销策略制定

京东搜索商品列表接口是京东开放平台提供的一种API接口&#xff0c;通过调用该接口&#xff0c;开发者可以获取京东平台上商品的列表数据&#xff0c;包括商品的标题、价格、库存、月销量、总销量、详情描述、图片等信息。 接口的主要作用包括&#xff1a; 市场调研&#xff…

OSPF下的MGRE实验

一、实验要求 1、R1-R3-R4构建全连的MGRE环境 2、R1-R5-R6建立hub-spoke的MGRE环境&#xff0c;其中R1为中心 3、R1-R3...R6均存在环回网段模拟用户私网&#xff0c;使用OSPF使全网可达 4、其中R2为ISP路由器&#xff0c;仅配置IP地址 二、实验拓扑图 三、实验配置 1、给各路…

iPortal如何灵活设置用户名及密码的安全规则

作者&#xff1a;yx 目录 前言 一、配置文件介绍 1、<passwordRules>节点 注意事项&#xff1a; 2、<usernameRules>节点 二、应用实例 1、配置文件设置 2、验证扩展结果 三、结果展示 前言 SuperMap iPortal提供了扩展账户信息合规度校验规则的能力&#…

一名优秀的C++人员是怎么炼成的?

一名优秀的C人员是怎么炼成的? 优秀的程序员都是解决各种bug锻炼出来的&#xff0c;程序员每天的工作大部分时间都是在解决各种bug, 所以说多做项目才是提升能力的唯一途径&#xff0c;要不然就是花架子&#xff0c;各种技术名词、源码整的很溜&#xff0c;一如果不是喜欢 C …

WPF中依赖属性及附加属性的概念及用法

完全来源于十月的寒流&#xff0c;感谢大佬讲解 依赖属性 由依赖属性提供的属性功能 与字段支持的属性不同&#xff0c;依赖属性扩展了属性的功能。 通常&#xff0c;添加的功能表示或支持以下功能之一&#xff1a; 资源数据绑定样式动画元数据重写属性值继承WPF 设计器集成 …

阴虱是怎么长出来的?皮肤性病科主任谭巍讲述五大因素

阴虱&#xff0c;是一种皮肤接触性传染性寄生虫病&#xff0c;在卫生情况不好的前提下有感染阴虱的可能性。人在感染阴虱后会对身心健康带来负面影响&#xff0c;所产生的临床症状会直接影响感染者的工作生活&#xff0c;所以日常应注意预防阴虱病。 然而&#xff0c;到现在还…

AI时代项目经理与架构师的成长之道:ChatGPT让你插上翅膀

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 在AI时代&#xff0c;项…

Vue3.0 声明式导航,编程式导航,路由,路由拦截案例

项目结构 App.vue&#xff1a;根组件 <template><div><router-view></router-view><Tabbar></Tabbar></div> </template> <script setup> import Tabbar from ../src/views/Tabbar.vue; //底部选项卡 import Home from…

Android T窗口动画添加移除流程(更新中)

APP侧窗口动画demo 如何创建一个窗口动画&#xff1f;我们通过先从APP创建一个窗口&#xff0c;以这个窗口的创建过程的窗口动画为例 这个demo就是点击BUTTON显示窗口&#xff0c;点击CLOSE WINDOW关闭窗口&#xff0c;下面简述关键代码 //定义WindowManager和LayoutParams…

Go:如何在GoLand中引用github.com中的第三方包

本篇博客主要介绍如何在GoLand中引入github.com中的第三方包。具体步骤如下&#xff1a; 正文 (1) 先在GoLand中打开go的工作区目录(即环境变量$GOPATH设置的变量)。如图&#xff1a; 关于工作区目录中的三个子目录: bin: 保存已编译的二进制可执行程序&#xff1b;pkg: 保…

深度学习之基于Tensorflow卷积神经网络花卉识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 深度学习是一种机器学习方法&#xff0c;它通过模拟人脑神经网络的结构和功能来实现对数据的自动分析和学习。卷积神…

SpringCloud——服务网关——GateWay

1.GateWay是什么&#xff1f; gateway也叫服务网关&#xff0c;SpringCloud GateWay使用的是Webflux中的reactor-netty响应式编程组件&#xff0c;底层使用了Netty通讯框架。 gateway的功能有反向代理、鉴权、流量控制、熔断、日志监控...... 2.为什么不使用Zuul&#xff1f…

EasyExcel 导出冻结指定行

导出的实体类 package org.jeecg.modules.eis.test;import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.*; import lombok.Getter; import lombok.Setter; import org.apache.poi.ss.usermodel.HorizontalAlignment;import…

Android Studio代码无法自动补全

Android Studio代码自动无法补全问题解决 在写layout布局文件时&#xff0c;代码不提示&#xff0c;不自动补全&#xff0c;可以采用如下方法&#xff1a; 点击File—>Project Structure&#xff0c;之后如图所示&#xff0c;找到左侧Modules&#xff0c;修改SDK版本号&…

Android笔记:(最全)判断网线是否插入方法

1.通过调用命令: cat /sys/class/net/eth0/carrier1.1在java代码中执行adb命令: private fun execCommand(command: String?): String {val runtime

【算法秘籍】藏在0和1之间的秘密,助你码出优秀人生

《算法秘籍》双十一 5折购书&#xff0c;就在京东商城 数据结构和算法是计算机科学的基石&#xff0c;是计算机的灵魂&#xff0c;要想成为计算机专业人员&#xff0c;学习和掌握算法是十分必要的。不懂数据结构和算法的人不可能写出效率更高的代码。计算机科学的很多新行业都离…

python加上ffmpeg实现音频分割

前言: 这是一个系列的文章,主要是使用python加上ffmpeg来对音视频文件进行处理,包括音频播放、音频格式转换、音频文件分割、视频播放等。 系列文章链接: 链接1: python使用ffmpeg来制作音频格式转换工具(优化版) 链接2:<Python>PyQt5+ffmpeg,简单视频播放器的编写(…

虚拟环境中使用的Python不是当前虚拟环境的,解决方法

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 在虚拟环境中使用的python和pip不是虚拟环境的pip安装不到当前的虚拟环境中…等 解决方法 1. 解决办法 打开配置文件 vim ~/.bashrc把如下代码注释即…

如何进行单病种质控上报管理

过程质量管理发展历程 单病种质量管理兴起之初&#xff0c;医疗机构多强调致残率、致死率、平均住院日、治愈好转率等结果性指标。这些指标主观性强&#xff0c;且为事后管理&#xff0c;无法及时发现问题&#xff0c;具有滞后性。 《卫生部办公厅关于开展单病种质量管理控制…

vue开发环境搭建部署(mac版)

前言 目前后端工作越来越少了&#xff0c;年底了&#xff0c;为了先过验收。项目负责人、产品、需求制定的方案就是先做假页面&#xff0c;所以前端的活多点。 其实现在不喜欢搞前端&#xff0c;原因很多&#xff0c;但是感觉现在似乎流行的码林绝学又是九九归一的瓶颈期…