ThreadPoolExecutor - 管理线程池的核心类

下面是使用给定的初始参数创建一个新的 ThreadPoolExecutor (构造方法)。

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

形参:

  • corePoolSize – 要保留在池中的线程数,即使它们处于空闲状态,除非 allowCoreThreadTimeOut 被设置了。
    allowCoreThreadTimeOut 是一个开关,用于控制核心线程是否可以在空闲状态下超时并被终止。默认情况下,allowCoreThreadTimeOut 是 false,这意味着核心线程不会因为空闲而超时被销毁。如果你调用
    setAllowCoreThreadTimeOut(true),那么核心线程也会像非核心线程一样,在空闲一段时间后(由
    keepAliveTime 和 unit 参数指定)被终止。
  • maximumPoolSize – 池中允许的最大线程数
  • keepAliveTime – 当线程数大于核心数时,这是多余的空闲线程在终止之前等待新任务的最长时间。
  • unit – 参数的时间 keepAliveTime 单位
  • workQueue – 用于在任务执行之前保存任务的队列。这个队列将仅保存通过 execute 方法提交的 Runnable 任务和通过
    submit 方法提交的 Runnable 或 Callable 任务。 execute 方法只接受 Runnable 任务。execute 方法没有返回值。适用于不需要返回结果的任务。
    submit 方法可以接受 Runnable 或 Callable 任务。submit 方法返回一个 Future 对象。
    如果提交的是 Runnable 任务,Future.get() 方法返回 null。
    如果提交的是 Callable 任务,Future.get() 方法返回 call 方法的返回值。
    适用于需要返回结果或检查任务状态的任务。
  • threadFactory – 执行器创建新线程时使用的工厂
  • handler – 当线程边界和队列容量已达到上限导致执行被阻塞时使用的处理程序。 handler 是
    RejectedExecutionHandler 接口的实现类对象。

在这里插入图片描述
RejectedExecutionHandler 接口的 rejectedExecution() 方法一共有四种默认实现:
在这里插入图片描述

在这里插入图片描述

  1. AbortPolicy - Abort 意思为中止
  • 类名:java.util.concurrent.ThreadPoolExecutor.AbortPolicy
  • 描述:这种策略在任务不能被执行时,会抛出 RejectedExecutionException 异常。它是默认的拒绝策略。
    使用场景:适用于不能丢弃任务且需要立即知道任务被拒绝的情况。
public static class AbortPolicy implements RejectedExecutionHandler {public AbortPolicy() { }public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {throw new RejectedExecutionException("Task " + r.toString() +" rejected from " +e.toString());}
}
  1. CallerRunsPolicy
  • 类名:java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy
  • 描述:这种策略在任务不能被执行时,会由提交任务的线程(通常是调用 execute 方法的线程)来执行该任务。这种策略可以有效降低新任务的流量,避免任务丢失。
    使用场景:适用于可以接受任务执行延迟但不希望任务被丢弃的情况。
public static class CallerRunsPolicy implements RejectedExecutionHandler {public CallerRunsPolicy() { }public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {r.run();}}
}
  1. DiscardOldestPolicy
  • 类名:java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy
  • 描述:这种策略在任务不能被执行时,会丢弃队列中最旧的未处理任务,然后尝试重新提交被拒绝的任务。
    使用场景:适用于希望优先处理新任务可以接受丢弃旧任务的情况。
public static class DiscardOldestPolicy implements RejectedExecutionHandler {public DiscardOldestPolicy() { }public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {e.getQueue().poll();e.execute(r);}}
}
  1. DiscardPolicy
  • 类名:java.util.concurrent.ThreadPoolExecutor.DiscardPolicy
  • 描述:这种策略在任务不能被执行时,会直接丢弃被拒绝的任务,不会有任何异常抛出。
    使用场景:适用于可以接受任务丢弃且不希望处理被拒绝任务的情况。
public static class DiscardPolicy implements RejectedExecutionHandler {public DiscardPolicy() { }public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {// Do nothing}
}

总结:

  • AbortPolicy:直接抛出 RejectedExecutionException 异常。
  • CallerRunsPolicy:由提交任务的线程执行被拒绝的任务。
  • DiscardOldestPolicy:丢弃队列中最旧的任务,然后重新提交被拒绝的任务。
  • DiscardPolicy:直接丢弃被拒绝的任务,不抛出异常。

下面是四种对于上述的ThreadPoolExecutor的封装,ExecutorService是线程服务对象

  1. 创建固定数量的线程对象newFixedThreadPool()
ExecutorService executorService = Executors.newFixedThreadPool(3);
    /**创建一个线程池,该线程池重用在共享的无界队列上运行的固定数量的线程。在任何时候,大多数 nThreads 线程都将是活动的去处理任务。如果在所有线程都处于活动状态时提交了其他任务,它们将在队列中等待,直到线程可用。如果某个线程在关闭之前由于执行期间的故障而终止,那么如果需要执行后续任务,将会有一个新的线程替代它的位置。这段话解释了固定大小线程池的一个重要特性:线程池会维护固定数量的线程,即使其中某个线程由于运行时的异常或错误而终止,线程池也会创建一个新的线程来替换它,从而确保线程池中始终有固定数量的线程来处理任务。形参:nThreads – 池中的线程数返回值:新创建的线程池抛出:IllegalArgumentException –如果 nThreads <= 0*/public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS, // 毫秒new LinkedBlockingQueue<Runnable>());}

ThreadPoolExecutor(nThreads)
核心线程数:nThreads
最大线程数:nThreads
队列类型:LinkedBlockingQueue(无界队列)FIFO先进先出队列
行为:固定数量的线程处理任务。如果所有线程都在忙碌,新任务会被放入无界队列中等待。
适用场景:适用于需要稳定的线程数量来处理较为均匀的任务负载的场景。

  1. 根据需求动态创建线程newCachedThreadPool, 创建的线程可以重复使用,只是当目前线程不够了他会动态增加线程
ExecutorService executorService = Executors.newCachedThreadPool();
/*
创建一个可以根据需要创建新线程的线程池,但如果之前构造的线程可用,则会重用这些线程。
这种线程池通常会提升那些执行许多短暂异步任务的程序的性能。
调用 execute 方法时,如果有可用的线程,会重用之前构造的线程。如果没有可用的线程,则会创建一个新线程并添加到线程池中。未使用超过60秒的线程会被终止并从缓存中移除。
因此,一个长时间处于空闲状态的线程池将不会消耗任何资源。
需要注意的是,可以使用 ThreadPoolExecutor 构造函数创建具有类似属性但不同细节(例如超时参数)的线程池。返回值:
新创建的线程池
*/
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}

newCachedThreadPool()
核心线程数:0
最大线程数:Integer.MAX_VALUE
队列类型:SynchronousQueue(不存储任务的队列,每次插入操作都必须等待对应的删除操作,反之亦然)。
每个 put 操作(插入任务)必须等待一个 take 操作(移除任务),相应地,每个 take 操作必须等待一个 put 操作。换句话说,生产者线程和消费者线程必须直接在队列上进行任务的交接。
行为:线程池可根据需求动态创建新线程,闲置超过 60 秒的线程会被终止并移出缓存。
适用场景:适用于大量短期异步任务或任务负载波动较大的场景。

newCachedThreadPool() 的工作原理:
① 任务提交:
当一个任务被提交到 newCachedThreadPool() 时,它会尝试将任务放入 SynchronousQueue。
由于 SynchronousQueue 不存储任务,这意味着必须有一个线程立即接收这个任务。
② 线程创建:
如果当前没有空闲线程能够立即接收任务,newCachedThreadPool() 会创建一个新的线程来处理这个任务。
这种机制确保了任务可以尽快得到处理。
③ 线程回收:
新创建的线程如果在闲置超过 60 秒后没有接收到新的任务,就会被终止并移出线程池。
这有助于释放资源,避免不必要的线程占用。

newCachedThreadPool() 完全依赖非核心线程来处理任务

  1. 单一线程newSingleThreadExecutor
ExecutorService executorService = Executors.newSingleThreadExecutor();
/*
创建一个 Executor,它使用单个工作线程从一个无界队列中获取任务进行操作。
(但是请注意,如果这个单个线程在执行过程中因为故障而在关闭之前终止了,那么如果需要执行后续任务,将会有一个新的线程替代它的位置。)
任务保证按顺序执行,并且在任何给定时间点,不会有超过一个任务在运行。
与功能相似的 newFixedThreadPool(1) 不同,返回的执行器保证不会被重新配置为使用额外的线程。返回值:
新创建的单线程执行器
*/
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS, // 毫秒new LinkedBlockingQueue<Runnable>()));}
private static class FinalizableDelegatedExecutorServiceextends DelegatedExecutorService {FinalizableDelegatedExecutorService(ExecutorService executor) {super(executor);}@SuppressWarnings("deprecation")protected void finalize() {super.shutdown();}}
private static class DelegatedExecutorServiceimplements ExecutorService {private final ExecutorService e;DelegatedExecutorService(ExecutorService executor) { e = executor; }

newSingleThreadExecutor()
核心线程数:1
最大线程数:1
队列类型:LinkedBlockingQueue(无界队列)
行为:始终只有一个线程执行任务,任务按提交顺序执行。如果线程因故障终止,会创建一个新线程来替代它。
适用场景:适用于需要按顺序执行任务的场景,并且在同一时间只需要一个线程执行任务。

newFixedThreadPool(1):虽然初始时只有一个线程,但它是使用 ThreadPoolExecutor 实现的,理论上可以通过调用 setCorePoolSize 和 setMaximumPoolSize 方法来重新配置线程池的线程数量。
也就是说,虽然默认情况下只有一个线程,但你可以在运行时增加线程池中的线程数量。
newSingleThreadExecutor():这个执行器保证始终只有一个线程,无法通过重新配置来增加线程数量。
它的实现确保了线程池的单线程性质是不可更改的。

  1. 定时调度线程 newScheduledThreadPool, 线程有3个,但是线程在什么时候执行我们可以去定义他
ExecutorService executorService = Executors.newScheduledThreadPool(3);
/*创建一个线程池,该线程池可以计划命令在给定延迟后运行,或定期执行。形参:corePoolSize – 池中要保留的线程数,即使它们处于空闲状态返回值:新创建的定时线程池抛出:IllegalArgumentException –如果 corePoolSize < 0
*/
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);}
public class ScheduledThreadPoolExecutorextends ThreadPoolExecutorimplements ScheduledExecutorService {
/*使用给定的核心池大小创建一个新 ScheduledThreadPoolExecutor 池。形参:corePoolSize – 要保留在池中的线程数,即使它们处于空闲状态,除非 allowCoreThreadTimeOut 已设置抛出:IllegalArgumentException –如果 corePoolSize < 0
*/
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,  // DEFAULT_KEEPALIVE_MILLIS = 10Lnew DelayedWorkQueue());  // super父类对象是ThreadPoolExecutor// 相当于:// public ThreadPoolExecutor(int corePoolSize,//                      int maximumPoolSize,//                       long keepAliveTime,//                      TimeUnit unit,//                      BlockingQueue<Runnable> workQueue) {// this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,//      Executors.defaultThreadFactory(), defaultHandler);}}}

newScheduledThreadPool(int corePoolSize) 方法用于创建一个定时线程池。
ScheduledThreadPoolExecutor 类继承自 ThreadPoolExecutor,并添加了对定时任务的支持。
核心线程数由 corePoolSize 决定,最大线程数为 Integer.MAX_VALUE
非核心线程的默认存活时间是 10 毫秒。
无界队列:DelayedWorkQueue 是一个无界队列,适用于存储定时任务和周期性任务。即使队列是无界的,它主要是一个优先级队列(基于任务的预定执行时间),并且不会因为任务太多而导致线程池拒绝任务。
超出线程池和等待队列容量的任务会被拒绝,并抛出异常。

newScheduledThreadPool(corePoolSize)
核心线程数:corePoolSize
最大线程数:Integer.MAX_VALUE
队列类型:DelayedWorkQueue(无界优先级队列,基于任务的预定执行时间)
行为:支持定时任务和周期性任务的线程池,核心线程数由 corePoolSize 决定,超出线程池和等待队列容量的任务会被拒绝并抛出异常。线程池可根据需求动态创建新的非核心线程,闲置超过 10 毫秒的线程会被终止并移出缓存,虽然话是这么说,但是由于 DelayedWorkQueue 是一个无界队列,通常情况下不会出现任务队列满的情况,因此非核心线程在 ScheduledThreadPoolExecutor 中被使用的机会较少,就主要还是依赖corePoolSize指定的核心线程来运行任务。因为核心线程先处理不完,然后把任务放到等待队列,等待队列也满了才开非核心线程,我是这样理解的。
适用场景:适用于需要在特定时间点或周期性执行任务的场景。

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

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

相关文章

【Python】搭建属于自己 AI 机器人

目录 前言 1 准备工作 1.1 环境搭建 1.2 获取 API KEY 2 写代码 2.1 引用库 2.2 创建用户 2.3 创建对话 2.4 输出内容 2.5 调试 2.6 全部代码 2.7 简短的总结 3 优化代码 3.1 规范代码 3.1.1 引用库 3.1.2 创建提示词 3.1.3 创建模型 3.1.4 规范输出&#xf…

Git详细安装和使用教程

文章目录 准备工作-gitee注册认识及安装GitGit配置用户信息本地初始化Git仓库记录每次更新到仓库查看及切换历史版本Git忽略文件和查看文件状态Git分支-查看及切换Git分支-创建分支Git分支-合并及删除分支Git分支-命令补充Git分支-冲突需求: 准备工作-gitee注册 传送门: gite…

HDF4文件转TIF格式

HDF4 HDF4&#xff08;Hierarchical Data Format version 4&#xff09;是一种用于存储和管理机器间数据的库和多功能文件格式。它是一种自描述的文件格式&#xff0c;用于存档和管理数据。 HDF4与HDF5是两种截然不同的技术&#xff0c;HDF5解决了HDF4的一些重要缺陷。因此&am…

[终端安全]-3 移动终端之硬件安全(TEE)

&#xff08;参考资料&#xff1a;TrustZone for V8-A. pdf&#xff0c;来源ARM DEVELOPER官网&#xff09; TEE&#xff08;Trusted Execution Environment&#xff0c;可信执行环境&#xff09;是用于执行敏感代码和处理敏感数据的独立安全区域&#xff1b;以ARM TrustZone为…

cs231n作业1——Softmax

参考文章&#xff1a;cs231n assignment1——softmax Softmax softmax其实和SVM差别不大&#xff0c;两者损失函数不同&#xff0c;softmax就是把各个类的得分转化成了概率。 损失函数&#xff1a; def softmax_loss_naive(W, X, y, reg):loss 0.0dW np.zeros_like(W)num_…

信号与系统笔记分享

文章目录 一、导论信号分类周期问题能量信号和功率信号系统的线性判断时变&#xff0c;时不变系统因果系统判断记忆性系统判断稳定性系统判断 二、信号时域分析阶跃函数冲激函数取样性质四种特性1 筛选特性2 抽样特性3 展缩特性4 卷积特性卷积作用 冲激偶函数奇函数性质公式推导…

Ubuntu 20.04下多版本CUDA的安装与切换 超详细教程

目录 前言一、安装 CUDA1.找到所需版本对应命令2.下载 .run 文件3.安装 CUDA4.配置环境变量4.1 写入环境变量4.2 软连接 5.验证安装 二、安装 cudnn1.下载 cudnn2.解压文件3.替换文件4.验证安装 三、切换 CUDA 版本1.切换版本2.检查版本 前言 当我们复现代码时&#xff0c;总会…

彻底解决Path with “WEB-INF“ or “META-INF“: [WEB-INF/views/index.jsp]

背景描述 项目使用的是springboot2jsp的架构。以前好好的项目复制了一份&#xff0c;然后就无法访问报错。百度了好久都乱七八糟的&#xff0c;还没有解决问题。错误消息如下&#xff1a; 2024-07-05 15:45:51.335 INFO [http-nio-12581-exec-1]org.springframework.web.ser…

Linux服务器使用总结-不定时更新

# 查看升级日志 cat /var/log/dpkg.log |grep nvidia|grep libnvidia-common

阶段三:项目开发---搭建项目前后端系统基础架构:任务13:实现基本的登录功能

任务描述 任务名称&#xff1a; 实现基本的登录功能 知识点&#xff1a; 了解前端Vue项目的基本执行过程 重 点&#xff1a; 构建项目的基本登陆功能 内 容&#xff1a; 通过实现项目的基本登录功能&#xff0c;来了解前端Vue项目的基本执行过程&#xff0c;并完成基…

firewalld(8) policies

简介 前面的文章中我们介绍了firewalld的一些基本配置以及NAT的相关配置。在前面的配置中&#xff0c;我们所有的策略都是与zone相关的&#xff0c;例如配置的rich rule&#xff0c;--direct,以及NAT,并且这些配置都是数据包进入zone或者从zone发出时设置的策略。 我们在介绍…

昇思25天学习打卡营第15天 | Vision Transformer图像分类

内容介绍&#xff1a; 近些年&#xff0c;随着基于自注意&#xff08;Self-Attention&#xff09;结构的模型的发展&#xff0c;特别是Transformer模型的提出&#xff0c;极大地促进了自然语言处理模型的发展。由于Transformers的计算效率和可扩展性&#xff0c;它已经能够训练…

在VMware虚拟机的创建以及安装linux操作系统

一、创建虚拟机 1.双击打开下载好的VMware Workstation软件 2.点击“创建新的虚拟机” 3.根据个人选择需要创建的虚拟机&#xff0c;点击下一步 4.直接点击下一步 5.选择稍后安装操作系统&#xff0c;点击下一步 、 6.选择需要的操作系统&#xff0c;点击下一步 7.根据…

YOLOv8改进---BiFPN特征融合

一、BiFPN原理 1.1 基本原理 BiFPN&#xff08;Bidirectional Feature Pyramid Network&#xff09;&#xff0c;双向特征金字塔网络是一种高效的多尺度特征融合网络&#xff0c;其基本原理概括分为以下几点&#xff1a; 双向特征融合&#xff1a;BiFPN允许特征在自顶向下和自…

【踩坑】修复pyinstaller报错 No module named pkg_resources.extern

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 报错如下&#xff1a; 修复方法&#xff1a; pip install --upgrade setuptools pippyinstaller -F -w main.py --hidden-importpkg_resources.py2_wa…

算法系列--分治排序|归并排序|逆序对的求解

一.基本概念与实现 归并排序(mergeSort)也是基于分治思想的一种排序方式,思路如下: 分解:根据中间下标mid将数组分解为两部分解决:不断执行上述分解过程,当分解到只有一个元素时,停止分解,此时就是有序的合并:合并两个有序的子区间,所有子区间合并的结果就是原问题的解 归并…

【TB作品】51单片机 Proteus仿真 00002仿真-智能台灯色调倒计时光强

实验报告&#xff1a;基于51单片机的智能台灯控制系统 背景 本实验旨在设计一个基于51单片机的智能台灯控制系统&#xff0c;该系统可以通过按键进行手动控制&#xff0c;并能根据环境光强度自动调节台灯亮度。此外&#xff0c;系统还具备倒计时关灯功能。 器件连接 51单片…

Xilinx FPGA:vivado关于真双端口的串口传输数据的实验

一、实验内容 用一个真双端RAM&#xff0c;端口A和端口B同时向RAM里写入数据0-99&#xff0c;A端口读出单数并存入单端口RAM1中&#xff0c;B端口读出双数并存入但端口RAM2中&#xff0c;当检测到按键1到来时将RAM1中的单数读出显示到PC端&#xff0c;当检测到按键2到来时&…

强化学习的数学原理:时序差分算法

概述 之前第五次课时学习的 蒙特卡洛 的方法是全课程当中第一次介绍的第一种 model-free 的方法&#xff0c;而本次课的 Temporal-Difference Learning 简称 TD learning &#xff08;时序差分算法&#xff09;就是第二种 model-free 的方法。而对于 蒙特卡洛方法其是一种 non…

QWidget窗口抗锯齿圆角的一个实现方案(支持子控件)2

QWidget窗口抗锯齿圆角的一个实现方案&#xff08;支持子控件&#xff09;2 本方案使用了QGraphicsEffect&#xff0c;由于QGraphicsEffect对一些控件会有渲染问题&#xff0c;比如列表、表格等&#xff0c;所以暂时仅作为研究&#xff0c;优先其他方案 在之前的文章中&#…