线程池 ThreadPoolExecutor 配置参数详解

《开发语言-Java》

在这里插入图片描述

线程池 ThreadPoolExecutor 参数详解

  • 一、引言
  • 二、主要内容
    • 2.1 核心构造函数
    • 2.2 核心线程数
    • 2.3 最大线程数
    • 2.4 空闲线程存活时间
    • 2.5 keepAliveTime 的时间单位
    • 2.6 核心线程在空闲时的回收策略
    • 2.7 工作队列
    • 2.8 线程工厂
    • 2.9 拒绝策略
  • 三、总结

一、引言

提到 Java 线程池,就不得不说 ThreadPoolExecutor,它是 Java 并发包 java.util.concurrent 中的一个类,提供一个高效、稳定、灵活的线程池实现,用于实现多线程并发执行任务,提高应用程序的执行效率。

在《任务执行与Executor框架》中,Huazie 介绍了通过 java.util.concurrent.Executors 中的静态工厂方法来创建线程池,而这个线程池实现就是 ThreadPoolExecutor

ThreadPoolExecutor 提供了一系列参数和配置选项,开发人员可以根据应用的需求来定制线程池的行为。

本篇就将详细介绍线程池 ThreadPoolExecutor 中的各种配置参数。

二、主要内容

注意: 以下涉及代码,均来自 JDK 1.8,其他版本如有出入,请自行查看

2.1 核心构造函数

话不多说,先来查看 ThreadPoolExecutor 的核心构造函数:

在这里插入图片描述

上述构造函数中的 7 个参数就是下面将要重点介绍的线程池 ThreadPoolExecutor 的核心配置参数了。

2.2 核心线程数

private volatile int corePoolSize;

corePoolSize 变量就是 核心线程数,即在没有设置allowCoreThreadTimeOuttrue 的情况下,需要保持存活的最小工作线程数量。

翻看 ThreadPoolExecutorexecute(Runnable command) 方法的源码,如下:

在这里插入图片描述

上述截图代码可以看出: 如果运行的线程数少于核心线程数,则为当前任务启动一个新的核心线程。

调用 addWorker 方法会原子性地检查 runStateworkerCount,从而防止在不应该添加线程时发出错误警报【这时 addWorker 方法会返回 false】。

可以通过 setCorePoolSize(int corePoolSize) 方法来重新设置核心线程数,如下图所示:

在这里插入图片描述

setCorePoolSize 方法将覆盖构造函数中设置的核心线程数。如果新值小于当前值,多余的现有线程将在它们下次变为空闲时被终止。如果新值更大,将根据需要启动新线程来执行任何排队的任务。

2.3 最大线程数

private volatile int maximumPoolSize;

maximumPoolSize 变量就是线程池允许的最大线程数。

可以通过 setMaximumPoolSize(int maximumPoolSize) 方法来重新设置线程池允许的最大线程数,如下图所示:

setMaximumPoolSize 方法将覆盖构造函数中设置的最大线程数。如果新值小于当前值,多余的现有线程将在它们下次变为空闲时被终止。

2.4 空闲线程存活时间

private volatile long keepAliveTime;

keepAliveTime 变量就是空闲线程存活时间【即空闲线程等待工作的超时时间(以纳秒为单位)】。当线程池中的线程数量超过 核心线程数 或者 允许核心线程超时 时,线程将使用此超时时间。否则,它们将无限期地等待新工作。

可以通过 setKeepAliveTime(long time, TimeUnit unit) 方法来重新设置空闲线程存活时间,如下图所示:

在这里插入图片描述

setKeepAliveTime 方法会覆盖在构造函数中设置的空闲线程存活时间。如果当前池中有多于核心数量的线程,在等待这段时间而没有处理任务之后,多余的线程将会被终止。

2.5 keepAliveTime 的时间单位

long keepAliveTime;
TimeUnit unit;
// 空闲线程等待工作的超时时间
this.keepAliveTime = unit.toNanos(keepAliveTime);

TimeUnitjava.util.concurrent 包中的枚举类,用于表示给定粒度单位时间持续时间的类,并提供了一些实用方法来进行单位之间的转换,以及在这些单位中执行定时和延迟操作。TimeUnit 并不维护时间信息,而是帮助组织和使用可能在各种上下文中分别维护的时间表示。纳秒被定义为微秒的千分之一,微秒是毫秒的千分之一,毫秒是秒的千分之一,分钟是六十秒,小时是六十分钟,天是二十四小时。

unit.toNanos 用于将 keepAliveTime 的参数值转换为纳秒值。

另外,在源码注释中有如下一段话:

there is no guarantee that a particular timeout implementation 
will be able to notice the passage of time 
at the same granularity as the given TimeUnit.

翻译中文,大概意思就是:

特定的超时实现可能无法保证能够以与给定TimeUnit相同的粒度来感知时间的流逝。

这怎么来理解呢?

这句话是说,尽管 TimeUnit 允许你以不同的时间单位(如纳秒、微秒、毫秒等)指定超时时间,但实际的超时检测机制可能无法精确地按照这些单位来检测时间的流逝。操作系统和硬件通常有 最小时间片 的概念,即它们能够识别的时间单位的最小粒度。例如,某些系统可能只能精确到毫秒级别,而无法精确到更小的微秒或纳秒级别。这意味着即使请求一个非常短的超时(比如几纳秒),实际的等待时间可能会更长,因为系统无法检测到这么短的时间间隔。此外,线程调度和其他系统级别的延迟也可能影响超时的实际精度。即使指定的超时单位很小,其他因素(如线程切换、系统负载等)也可能导致实际的等待时间超过预期。

2.6 核心线程在空闲时的回收策略

private volatile boolean allowCoreThreadTimeOut;

如果为 false(默认值),即使核心线程处于空闲状态,它们也会保持活动状态。
如果为 true,核心线程会使用 keepAliveTime 来设置等待工作的超时时间。

可以通过 ThreadPoolExecutorallowCoreThreadTimeOut(boolean value) 方法进行设置。

在这里插入图片描述

2.7 工作队列

private final BlockingQueue<Runnable> workQueue;

workQueue 变量就是工作队列,它是一个阻塞队列,用于保存等待执行的任务并将其交给工作线程处理。

阅读相关源码注释中,可以看到如下一段话:

We do not require that workQueue.poll() returning null necessarily means that workQueue.isEmpty(), 
so rely solely on isEmpty to see if the queue is empty (which we must do for example when deciding 
whether to transition from SHUTDOWN to TIDYING). This accommodates special-purpose queues such as 
DelayQueues for which poll() is allowed to return null even if it may later return non-null when delays expire.

中文翻译,大概意思如下:

我们并不要求 workQueue.poll() 返回 null 必然意味着 workQueue.isEmpty(),因此仅依赖 isEmpty 来判断队列是否为空(例如,在决定是否从 SHUTDOWN 状态过渡到 TIDYING 状态时必须这样做)。这样可以适应特殊用途的队列,如 DelayQueue,即使它稍后可能会在延迟过期后返回非空值,但 poll() 也允许返回 null。

那这段注释,又该如何理解呢?

我们知道,当使用队列(如 workQueue)来管理待处理的任务时,通常会有一个或多个工作线程不断地从队列中检索任务来进行处理。poll() 方法通常用于从队列中检索下一个可用的元素,但它的行为可能会根据队列的类型而有所不同:

  • 在某些队列(如普通的 LinkedBlockingQueueArrayBlockingQueue)中,poll() 方法在队列为空时返回 null,表示没有更多的元素可供处理。在这种情况下,如果 poll() 返回 null,那么可以确定队列是空的,因为 poll() 的行为与 isEmpty() 方法的返回值一致。
  • DelayQueue 是一个特殊用途的队列,它允许延迟元素的可用性。在 DelayQueue 中,即使队列中可能还有未到期的元素(即元素还没有准备好被处理),poll() 方法也可能会返回 null。这也就说明 poll() 返回 null 并不一定意味着队列也是空的,因为可能还有未到期的元素在队列中。

2.8 线程工厂

private volatile ThreadFactory threadFactory;

threadFactory 变量就是线程工厂,所有线程都是使用这个工厂创建的(通过 addWorker 方法),默认使用 Executors.defaultThreadFactory() 来创建线程。

在这里插入图片描述
在这里插入图片描述

2.9 拒绝策略

private volatile RejectedExecutionHandler handler;

handler 变量就是 拒绝策略,即当执行过程中饱和或关闭时调用的处理程序。

当阻塞队列已满且无法创建新的线程时,线程池会调用拒绝策略来处理新提交的任务。

Java 线程池提供了几种不同的拒绝策略实现,如

  • AbortPolicy:默认策略,直接抛出 RejectedExecutionException 异常,阻止系统正常运行。
    在这里插入图片描述
    在这里插入图片描述
  • CallerRunsPolicy:只用调用者运行一些任务,如果线程池已满,则将任务回退到调用者执行。
    在这里插入图片描述
  • DiscardOldestPolicy:抛弃最老的任务请求,也就是即将被执行的任务。
    在这里插入图片描述
  • DiscardPolicy:直接丢弃任务,不给予任何处理,也不抛出异常。
    在这里插入图片描述

三、总结

本文 Huazie 基于线程池 ThreadPoolExecutor 的核心构造函数,详细介绍了它的一些关键配置参数。通过本文的介绍,相信大家能够对线程池 ThreadPoolExecutor 的配置参数有了更加清晰的理解,这有助于后续更深入地掌握线程池的运作原理。

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

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

相关文章

《QT实用小工具·三十一》基于QT开发的访客管理平台demo2

1、概述 源码放在文章末尾 该项目为访客管理平台demo&#xff0c;包含主界面、系统设置、警情查询、调试帮助、用户退出功能。 项目部分代码如下&#xff1a; #pragma execution_character_set("utf-8")#include "frmmain.h" #include "ui_frmmain…

js调用html页面需要隐藏某个按钮

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

Qt日志使用

QsLog使用 这篇讲qt的日志还是比较好的&#xff0c;可以在自己的函数里面配置这个日志框架实现自己所需的功能。 我接触的项目里面&#xff0c;假如有个函数功能执行错误了&#xff0c;我希望可以快速定位到这个错误&#xff0c;这个时候就需要到了日志&#xff0c;我咨询了有经…

Python测试转岗网络安全测试,挑战年薪30W+

有许多人问我安全测试前景怎么样&#xff1f; 目前&#xff0c;网络安全市场可大致分为17大安全领域、59个细分领域。不同领域大类核心技术相距甚远&#xff0c;因此绝大多数企业都选择专注于几个细分市场上。产品终端使用者主要以政企、军队、运营商、金融、医疗、教育、交通…

【技巧】PPT文件如何添加公司LOGO?

在工作上&#xff0c;我们经常要给PPT文件添加上公司的logo&#xff0c;如果一页一页添加不但耗时耗力&#xff0c;还容易有遗漏。那怎样快速给PPT添加logo呢&#xff1f;不清楚的小伙伴一起来看看如何吧&#xff01; 操作步骤&#xff1a; 1.打开PPT文件&#xff0c;点击菜单…

【DM8】ODBC

官网下载ODBC https://www.unixodbc.org/ 上传到linux系统中 /mnt下 [rootstudy ~]#cd /mnt [rootstudy mnt]# tar -zxvf unixODBC-2.3.12.tar.gz [rootstudy mnt]# cd unixODBC-2.3.12/ [rootstudy unixODBC-2.3.12]# ./configure 注意&#xff1a;若是报以上错 则是gcc未安…

【C语言】【数据结构】项目实践——贪吃蛇游戏(超详细)

前言 本篇博客我们来实现一个小游戏项目——贪吃蛇&#xff0c;相信肯定很多人都玩过&#xff0c;那么整个贪吃蛇是怎么实现出来的那&#xff0c;这个项目用到了很多方面的知识&#xff1a;C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API等。我们就通过这…

JAVA 集合框架(一) Collection集合详解和常用方法

Java集合框架&#xff08;Java Collections Framework&#xff09;是一个强大的、高度灵活的数据结构库&#xff0c;它为Java应用程序提供了组织、存储和操作对象集合的标准方法。 集合类体系结构 接口类&#xff1a; Collection: 是单例集合类的顶层接口&#xff0c;包括Lis…

【MIT6.824】lab3 Fault-tolerant Key/Value Service 实现笔记

引言 lab3A的实验要求如下&#xff1a; Your first task is to implement a solution that works when there are no dropped messages, and no failed servers. You’ll need to add RPC-sending code to the Clerk Put/Append/Get methods in client.go, and implement Pu…

算法课程笔记——pair的使用

先思考&#xff0c;为什么 STL 中的容器和算法都是用的左闭右开区间&#xff1f; | | | 这样迭代器只需要支持和!(或者<或者)操作就可以方便的进行区间遍历了。 其它区间设置的话&#xff0c;要么得支持<操作&#xff0c;要么得在循环体内&#xff0c;操作之前进行!判定。…

牛客2024 【牛客赛文X】春招冲刺 ONT34 加油站【中等 贪心 C++、Java、Go、PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/a013a0691a0343aeb262ca1450d2fe4e 思路 贪心&#xff1a; 如果总的gas小于走完全程的cost&#xff0c;直接返回-1不需要再找了 如果确保了可以走完一圈之后&#xff0c;那么从index 0开始找&#xff0c; 当g…

java-生产者消费者

目录 1.生产者消费者1.1生产者和消费者模式概述【应用】1.2生产者和消费者案例【应用】1.3生产者和消费者案例优化【应用】1.4阻塞队列基本使用【理解】1.5阻塞队列实现等待唤醒机制【理解】 1.生产者消费者 1.1生产者和消费者模式概述【应用】 概述 生产者消费者模式是一个十…

Linux软件包管理器yum—1

目录 一、Linux下软件安装的方式 二、yum 2.1查看yum已配置的源&#xff1a; 2.2查看yum配置文件&#xff1a; 2.3使用root用户安装软件&#xff1a; 2.4模糊搜索 2.5安装软件&#xff1a; 2.6卸载软件&#xff1a; 2.7扩展源&#xff1a; 2.8yum源更新&#xff1a; 一…

实验室三大常用仪器2---函数信号发生器的基本使用方法(笔记)

目录 函数信号发生器的基本使用方法 如何连接函数信号发生器和示波器 实验室三大常用仪器1---示波器的基本使用方法&#xff08;笔记&#xff09;-CSDN博客 实验室三大常用仪器3---交流毫伏表的使用方法&#xff08;笔记&#xff09;-CSDN博客 示波器是用来显示和测量信号的…

05-Logistic Softmax详解

Logistic Regression 本章我们来看另一个简单且强大的解决线性回归二元分类问题的算法&#xff0c; 即逻辑回归。不要望文生义&#xff0c; 逻辑回归虽然带回归这个字眼&#xff0c; 但它其实处理的是分类任务&#xff0c;即逻辑回归是一种分类模型&#xff0c; 而非回归模型&…

西夏区第三届中华诗词大会活动方案

活动流程/比赛规则 1.【13:30-14:10】 参赛选手签到&#xff1b;领取参赛号码牌&#xff1b;分组抽签&#xff1b;拍摄赛前感言&#xff0c;集体祝福口号&#xff1b; 2.【14:10-14:25】 熟悉设备、答题环节、题目设置等&#xff0c;走台演练 3.【14:25-14:30】 播放暖场视频…

怎么配置python

右键点击“计算机”&#xff0c;选择“属性”。 在左侧栏找到“高级系统设置”。 点击“环境变量”。 在系统变量中&#xff0c;双击“Path”。 在字符串的末尾&#xff0c;加一个分号; 然后再输入你安装python的路径&#xff0c;如图所示&#xff1a; 点击“确定”&#xff0…

logisim 图解超前进位加法器原理解释

鄙人是视频作者&#xff0c;文件在视频简介的网盘链接。 找规律图解超前进位加法器与原理解释_哔哩哔哩_bilibili 一句话就是“把能导致进位到这个位置的情况全都穷举一遍。” 穷举情况看图中算式。 视频讲解比较啰嗦。

C++修炼之路之继承<一>隐藏,赋值转换规则,继承关系

目录 前言 一&#xff1a;继承的概念和定义 1.概念 2.继承的定义 1.定义格式 2.继承关系和访问限定符 3.继承基类成员访问方式的变化 二&#xff1a;基类和派生类对象赋值转换 规则 三&#xff1a;继承中的作用域 规则 经典举例 经典例题--区分函数重载和隐藏…

PyQt介绍——QStackedWidget堆栈组件的介绍使用

QStackedWidget是一个堆栈窗口控件&#xff0c;用于管理多个堆叠的子部件。它只显示当前选中的子部件&#xff0c;而隐藏其余的子部件。 例子&#xff1a; ControlWidget窗口中&#xff0c;创建QStackedWidget&#xff0c;分别添加两个组件&#xff0c;为Test1Widget和Test2W…