线程池七个参数的含义

news2025/5/14 14:15:25

Java中的线程池里七个参数的以及其各自的含义

面试题:说一下线程池七个参数的含义?

所谓的线程池的 7 大参数是指,在使用 ThreadPoolExecutor 创建线程池时所设置的 7 个参数,如以下源码所示:

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

这 7 个参数分别是:

  1. corePoolSize:核心线程数。
  2. maximumPoolSize:最大线程数。
  3. keepAliveTime:空闲线程存活时间。
  4. TimeUnit:时间单位。
  5. BlockingQueue:线程池任务队列。
  6. ThreadFactory:创建线程的工厂。
  7. RejectedExecutionHandler:拒绝策略。

参数1:corePoolSize

核心线程数:是指线程池中长期存活的线程数。

这就好比古代大户人家,会长期雇佣一些“长工”来给他们干活,这些人一般比较稳定,无论这一年的活多活少,这些人都不会被辞退,都是长期生活在大户人家的。

参数2:maximumPoolSize

最大线程数:线程池允许创建的最大线程数量,当线程池的任务队列满了之后,可以创建的最大线程数。

这是古代大户人家最多可以雇佣的人数,比如某个节日或大户人家有人过寿时,因为活太多,仅靠“长工”是完不成任务,这时就会再招聘一些“短工”一起来干活,这个最大线程数就是“长工”+“短工”的总人数,也就是招聘的人数不能超过 maximumPoolSize。

注意事项

最大线程数 maximumPoolSize 的值不能小于核心线程数 corePoolSize,否则在程序运行时会报 IllegalArgumentException 非法参数异常,如下图所示:
在这里插入图片描述

参数3:keepAliveTime

空闲线程存活时间,当线程池中没有任务时,会销毁一些线程,销毁的线程数=maximumPoolSize(最大线程数)-corePoolSize(核心线程数)。

还是以大户人家为例,当大户人家比较忙的时候就会雇佣一些“短工”来干活,但等干完活之后,不忙了,就会将这些“短工”辞退掉,而 keepAliveTime 就是用来描述没活之后,短工可以在大户人家待的(最长)时间。

参数4:TimeUnit

时间单位:空闲线程存活时间的描述单位,此参数是配合参数 3 使用的。参数 3 是一个 long 类型的值,比如参数 3 传递的是 1,那么这个 1 表示的是 1 天?还是 1 小时?还是 1 秒钟?是由参数 4 说了算的。TimeUnit 有以下 7 个值:

  • TimeUnit.DAYS:天
  • TimeUnit.HOURS:小时
  • TimeUnit.MINUTES:分
  • TimeUnit.SECONDS:秒
  • TimeUnit.MILLISECONDS:毫秒
  • TimeUnit.MICROSECONDS:微妙
  • TimeUnit.NANOSECONDS:纳秒

参数5:BlockingQueue

在Java中,BlockingQueue是一个接口,它的实现类有ArrayBlockingQueue、DelayQueue、 LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue等,它们的区别主要体现在存储
结构上或对元素操作上的不同,但是对于take与put操作的原理,却是类似的,目的都是阻塞存取。

有界与无界

有界队列:就是有固定大小的队列。比如设定了固定大小的 LinkedBlockingQueue,又或者大小为 0,只是在生产者和消费者中做中转用的 SynchronousQueue。

无界队列:指的是没有设置固定大小的队列。这些队列的特点是可以直接入列,直到溢出。当然现实几乎不会有到这么大的容量(超过 Integer.MAX_VALUE),所以从使用者的体验上,就相当于 “无界”。比如没有设定固定大小的 LinkedBlockingQueue。

阻塞与非阻塞

阻塞和非阻塞指的是调用者(程序)在等待返回结果(或输入)时的状态。阻塞时,在调用结果返回前,当前线程会被挂起,并在得到结果之后返回。非阻塞时,如果不能立刻得到结果,则该调用者不会阻塞当前线程。因此对应非阻塞的情况,调用者需要定时轮询查看处理状态。

入队

add(E e):(非阻塞)调用offer但会根据offer结果,如果false抛出 IllegalStateException(“Queue full”)
offer(E e):(非阻塞)如果队列没满,立即返回true; 如果队列满了,立即返回false
put(E e):(阻塞)如果队列满了,一直阻塞,直到队列不满了或者线程被中断
offer(E e, long timeout, TimeUnit unit):在队尾插入一个元素,,如果队列已满,则进入等待,直到出现以下三种情况:
1.被唤醒
2.等待时间超时
3.当前线程被中断

出队

poll():(非阻塞)如果没有元素,直接返回null;如果有元素,出队
remove():(非阻塞)删除队列头元素,如果没有元素,返回false
take():(阻塞)如果队列空了,一直阻塞,直到队列不为空或者线程被中断
poll(long timeout, TimeUnit unit):如果队列不空,出队;如果队列已空且已经超时,返回null;如果队列已空且时间未超时,则进入等待,直到出现以下三种情况:
1.被唤醒
2.等待时间超时
3.当前线程被中断

查看元素

element(): 调用peek(),查看元素,拿到为null,抛出 NoSuchElementException。
peek():查看元素,不去除,如果拿不到则为null。

阻塞队列

阻塞队列:是一种特殊的队列,它在普通队列的基础上提供了两个附加功能。
在这里插入图片描述

即:

  1. 当队列为空的时候,获取队列中元素的消费者线程会被阻塞,同时唤醒生产者线程。
  2. 当队列满了的时候,向队列中添加元素的生产者线程被阻塞,同时唤醒消费者线程。

在线程池中,阻塞队列是用来存储线程池的所有待执行任务的队列。它可以设置以下几个值:

- ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
    特点:ArrayBlockingQueue底层是使用一个数组实现队列的,内部使用了一把锁对插入和取出做了限制,即插或者取的操作是原子性
    容量:需要指定一个大小,创建了无法修改
    元素:不允许为null的元素插入
- LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
    特点:内部有两把锁,即入队锁和出队锁(ReentrantLock+Condition),插入和取出各一把,互不打扰。两把锁来控制插入和取出数组阻塞唤醒。内部通过AtomicInteger count变量保证统计队列元素准确
    容量:默认为Integer.MAX_VALUE
    元素:不允许为null的元素插入
- SynchronousQueue:一个不存储元素的阻塞队列,即直接提交给线程不保持它们。
	一种无缓冲的等待队列,相对于有缓冲的BlockingQueue来说,少了一个中间经销商的环节(缓冲区)。消费者必须亲自去集市找到所要商品的直接生产者
    特点:一对一,生产者和消费者缺一就阻塞,存在公平和非公平两种
    容量:size默认为0,剩余容量也为0
    元素:不允许为null的元素插入
- PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
    特点:无界队列依赖Comparator来确保不同元素的排序位置,最大值不超过Integer.MAX_Value-8
    容量:默认大小为11,底层使用数组来存储,会扩容
    元素:不允许为null的元素插入
- DelayQueue:一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素。
    特点:存储Delayed元素,可实现延时等功能
    容量:默认为11,底层使用PriorityBlockingQueue来存储
    元素:不允许为null的元素插入,内部存储Delay的实现类元素
    take:内部使用priorityblockingqueue排序,根据getDelay判断剩余时间,只有当前到点了,才可以取出元素
- LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
	特点:BlockingDeque 类是一个双端队列,在不能够插入元素时,它将阻塞住试图插入元素的线程;在不能够抽取元素时,它将阻塞住试图抽取的线程。
	容量:可以指定队列的容量(防止过度膨胀),如果不指定,默认容量大小等于Integer.MAX_VALUE。
	元素:同时支持FIFO和FILO两种操作方式(即可以从队列的头和尾同时操作(插入/删除)),支持线程安全。
- LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。与SynchronousQueue类似,还含有非阻塞方法。
	public interface TransferQueue<E> extends BlockingQueue<E> {
        // 如果可能,立即将元素转移给等待的消费者。 
        // 如果存在消费者已经等待接收它(在 take 或 timed poll(long,TimeUnit)poll)中,则立即传送指定的元素,否则返回 false。
        boolean tryTransfer(E e);

        // 将元素转移给消费者,如果需要的话等待。 
        // 如果存在一个消费者已经等待接收它(在 take 或timed poll(long,TimeUnit)poll)中,则立即传送指定的元素,否则等待直到元素由消费者接收。
        void transfer(E e) throws InterruptedException;

        // 上面方法的基础上设置超时时间
        boolean tryTransfer(E e, long timeout, TimeUnit unit) throws InterruptedException;

        // 如果至少有一位消费者在等待,则返回 true
        boolean hasWaitingConsumer();

        // 返回等待消费者人数的估计值
        int getWaitingConsumerCount();
    }
	特点:实现了TransferQueue接口。TransferQueue接口继承了BlockingQueue,主要扩展了两个方法tryTransfer、transfer。
	对比:和SynchronousQueue.TransferQueue(公平模式)相比,它是可以统计长度,可以进行查询的;和LinkedBlockingQueue相比,它拥有更高的性能(使用CAS自旋);和ConcurrentLinkedQueue相比,它拥有阻塞功能。因此可以看作是ConcurrentLinkedQueue、SynchronousQueue、LinkedBlockingQueue的超集,作为对比学习。既然说到了,那就顺便说一下ConcurrentLinkedQueue吧。
	总结:
	ArrayBlockingQueue:需要创建队列数组长度。
    LinkedBlockingQueue:内部使用Node实现,默认大小Integer.MAX_VALUE。
    PriorityBlockingQueue:优先级队列,默认大小11,内部需实现Comparator来比较。
    DelayQueue:延时队列,元素需要实现Delayed,底层使用PriorityBlockingQueue,默认大小11。
    SynchronousQueue:交换队列,默认大小0,需同时存在生产者和消费者,否则任一都会阻塞
    LinkedTransferQueue:新增transfer方法,tryTransfer和transfer可以检测是否有线程在等待获取数据,如果检测到就立即发送新增的数据给这个线程获取而不用放入队列。
-----------------------------------------------------------------------------------------	
顺便提一下ConcurrentLinkedQueue。
- ConcurrentLinkedQueue:是一种非阻塞的无界的线程安全队列,与阻塞队列LinkedBlockingQueue相对应,ConcurrentLinkedQueue同样也是使用链表实现的FIFO队列,但不同的是它没有使用任何锁机制,而是用自旋+CAS来实现线程安全。
	特点:
.不允许null入列
.在入队的最后一个元素的next为null
.队列中所有未删除的节点的item都不能为null且都能从head节点遍历到
.删除节点是将item设置为null, 队列迭代时跳过item为null节点
.head节点跟tail不一定指向头节点或尾节点,可能存在滞后性 

比较常用的是 LinkedBlockingQueue,线程池的排队策略和 BlockingQueue 息息相关。

参数6:ThreadFactory

线程工厂:线程池创建线程时调用的工厂方法,通过此方法可以设置线程的优先级、线程命名规则以及线程类型(用户线程还是守护线程)等。线程工厂的使用示例如下:

public static void main(String[] args) {
    // 创建线程工厂
    ThreadFactory threadFactory = new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            // 创建线程池中的线程
            Thread thread = new Thread(r);
            // 设置线程名称
            thread.setName("Thread-" + r.hashCode());
            // 设置线程优先级(最大值:10)
            thread.setPriority(Thread.MAX_PRIORITY);
            //......
            return thread;
        }
    };
    // 创建线程池
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 0,TimeUnit.SECONDS, new LinkedBlockingQueue<>(),threadFactory); // 使用自定义的线程工厂
    threadPoolExecutor.submit(new Runnable() {
        @Override
        public void run() {
            Thread thread = Thread.currentThread();
            System.out.println(String.format("线程:%s,线程优先级:%d",
                                             thread.getName(), thread.getPriority()));
        }
    });
}

以上程序的执行结果如下:

在这里插入图片描述

从上述执行结果可以看出,自定义线程工厂起作用了,线程的名称和线程的优先级都是通过线程工厂设置的。

参数7:RejectedExecutionHandler

拒绝策略:当线程池的任务超出线程池队列可以存储的最大值之后,执行的策略。默认的拒绝策略有以下 4 种:

  • AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  • CallerRunsPolicy:使用当前调用的线程来执行此任务。
  • DiscardOldestPolicy:丢弃队列头部(最旧)的一个任务,并重新执行当前任务(重复此过程)。
  • DiscardPolicy:也是丢弃任务,但是不抛出异常。

线程池的默认策略是 AbortPolicy 拒绝并抛出异常。

案例分析

线程池中线程数小于corePoolSize时,新任务将创建一个新线程执行任务,不论此时线程池中是否存在空闲线程。

线程池中线程数达到corePoolSize时,新任务将被放入workQueue中,等待线程池中任务调度执行;

当workQueue已满,且maximumPoolSize>corePoolSize时,新任务会创建新线程执行任务;

当workQueue已满,且提交任务数超过maximumPoolSize,任务由RejectedExecutionHandler处理;

当线程池中线程数超过corePoolSize,且超过这部分的空闲时间达到keepAliveTime时,回收该线程;

如果设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize范围内的线程空闲时间达到keepAliveTime也将回收;

总结

本文介绍了线程池的 7 大参数:

  1. corePoolSize:核心线程数,线程池正常情况下保持的线程数,大户人家“长工”的数量。
  2. maximumPoolSize:最大线程数,当线程池繁忙时最多可以拥有的线程数,大户人家“长工”+“短工”的总数量。
  3. keepAliveTime:空闲线程存活时间,没有活之后“短工”可以生存的最大时间。
  4. TimeUnit:时间单位,配合参数 3 一起使用,用于描述参数 3 的时间单位。
  5. BlockingQueue:线程池的任务队列,用于保存线程池待执行任务的容器。
  6. ThreadFactory:线程工厂,用于创建线程池中线程的工厂方法,通过它可以设置线程的命名规则、优先级和线程类型。
  7. RejectedExecutionHandler:拒绝策略,当任务量超过线程池可以保存的最大任务数时,执行的策略。

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

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

相关文章

Windows suwellofd 阅读器-v5.0.25.0320

Windows suwellofd 阅读器 链接&#xff1a;https://pan.xunlei.com/s/VOO7tUkTHHTTjSe39CeVkUHbA1?pwd3ibx# OFD(Open Fixed-layout Document) &#xff0c; 数科OFD阅读器支持国标版式、可信阅读、是电子发票、电子证照&#xff0c;电子病历等电子文件理想阅读工具。 多格…

三大等待和三大切换

三大等待 1、三大等待&#xff1a;等待的方式有三种&#xff1a;强制等待&#xff0c;隐性等待&#xff0c;显性等待。 1、强制等待&#xff1a;time.sleep(2)&#xff0c;秒 优点&#xff1a;使用简单缺点&#xff1a;等待时间把握不准&#xff0c;容易造成时间浪费或者等待时…

告别定时任务!用Dagster监听器实现秒级数据响应自动化

在数据管道开发中&#xff0c;我们经常面临需要根据外部事件触发计算任务的场景。传统基于时间的调度方式存在资源浪费和时效性不足的问题。本文将通过Dagster的**传感器&#xff08;Sensor&#xff09;**功能&#xff0c;演示如何构建事件驱动的数据处理流程。 场景模拟&…

【Unity】打包TextMeshPro的字体

前言 在Unity中&#xff0c;TextMeshPro与常规 Text 组件相比提供了更高级的文本呈现功能&#xff0c;TextMesh Pro 可以处理各种语言&#xff0c;包括中文。我们可以轻松地在 Unity 项目中使用中文&#xff0c;而不必担心字体和布局问题。TextMeshPro需要的字体资源就需要我们…

51单片机实验五:A/D和D/A转换

一、实验环境与实验器材 环境&#xff1a;Keli&#xff0c;STC-ISP烧写软件,Proteus. 器材&#xff1a;TX-1C单片机&#xff08;STC89C52RC&#xff09;、电脑。 二、 实验内容及实验步骤 1.A/D转换 概念&#xff1a;模数转换是将连续的模拟信号转换为离散的数字信…

使用VHD虚拟磁盘安装双系统,避免磁盘分区

前言 很多时候&#xff0c;我们对现在的操作系统不满意,就想要自己安装一个双系统 但是安装双系统又涉及到硬盘分区,非常复杂,容易造成数据问题 虚拟机的话有经常用的不爽,这里其实有一个介于虚拟机和双系统之间的解决方法,就是使用虚拟硬盘文件安装系统. 相当于系统在机上…

Kafka消费者端重平衡流程

重平衡的完整流程需要消费者 端和协调者组件共同参与才能完成。我们先从消费者的视角来审视一下重平衡的流程。在消费者端&#xff0c;重平衡分为两个步骤&#xff1a;分别是加入组和等待领导者消费者&#xff08;Leader Consumer&#xff09;分配方案。这两个步骤分别对应两类…

Django之modelform使用

Django新增修改数据功能优化 目录 1.新增数据功能优化 2.修改数据功能优化 在我们做数据优化处理之前, 我们先回顾下传统的写法, 是如何实现增加修改的。 我们需要在templates里面新建前端的页面, 需要有新增还要删除, 比如说员工数据的新增, 那需要有很多个输入框, 那html…

云轴科技ZStack入选中国人工智能产业发展联盟《大模型应用交付供应商名录》

2025年4月8日至9日&#xff0c;中国人工智能产业发展联盟&#xff08;以下简称AIIA&#xff09;第十四次全体会议暨人工智能赋能新型工业化深度行&#xff08;南京站&#xff09;在南京召开。工业和信息化部科技司副司长杜广达&#xff0c;中国信息通信研究院院长、中国人工智能…

写论文时降AIGC和降重的一些注意事项

‘ 写一些研究成果&#xff0c;英文不是很好&#xff0c;用有道翻译过来句子很简单&#xff0c;句型很单一。那么你会考虑用ai吗&#xff1f; 如果语句太正式&#xff0c;高级&#xff0c;会被误判成aigc &#xff0c;慎重选择ai润色。 有的话就算没有用ai生成&#xff0c;但…

AI 编程工具—如何在 Cursor 中集成使用 MCP工具

AI 编程工具—如何在 Cursor 中集成使用 MCP工具 这里我们给出了常用的MCP 聚合工具,也就是我们可以在这些网站找MCP服务 这是一个MCP Server共享平台,用户可以在上面发布和下载MCP Server配置。在这里可以选择你需要的MCP 服务。 如果你不知道你的mcp 对应的server 名称也不…

《软件设计师》复习笔记(12.2)——成本管理、配置管理

目录 一、项目成本管理 1. 定义 2. 主要过程 3. 成本类型 4. 其他概念 真题示例&#xff1a; 二、软件配置管理 1. 定义 2. 主要活动 3. 配置项 4. 基线&#xff08;Baseline&#xff09; 5. 配置库类型 真题示例&#xff1a; 一、项目成本管理 1. 定义 在批准…

Spring 中的 @Cacheable 缓存注解

1 什么是缓存 第一个问题&#xff0c;首先要搞明白什么是缓存&#xff0c;缓存的意义是什么。 对于普通业务&#xff0c;如果要查询一个数据&#xff0c;一般直接select数据库进行查找。但是在高流量的情况下&#xff0c;直接查找数据库就会成为性能的瓶颈。因为数据库查找的…

settimeout和setinterval区别

1. setTimeout&#xff1a;单次延迟执行 语法&#xff1a; const timeoutId setTimeout(callback, delay, arg1, arg2, ...); 核心功能&#xff1a;在指定的 delay&#xff08;毫秒&#xff09;后&#xff0c;执行一次 callback 函数。 参数&#xff1a; callback&#x…

Kaamel隐私与安全分析报告:Microsoft Recall功能评估与风险控制

本报告对Microsoft最新推出的Recall功能进行了全面隐私与安全分析。Recall是Windows 11 Copilot电脑的专属AI功能&#xff0c;允许用户以自然语言搜索曾在电脑上查看过的内容。该功能在初次发布时因严重隐私和安全问题而备受争议&#xff0c;后经微软全面重新设计。我们的分析表…

Thymeleaf简介

在Java中&#xff0c;模板引擎可以帮助生成文本输出。常见的模板引擎包括FreeMarker、Velocity和Thymeleaf等 Thymeleaf是一个适用于Web和独立环境的现代服务器端Java模板引擎。 Thymeleaf 和 JSP比较&#xff1a; Thymeleaf目前所作的工作和JSP有相似之处&#xff0c;Thyme…

o3和o4-mini的升级有哪些亮点?

ChatGPT是基于OpenAI GPT系列的高性能对话生成AI&#xff0c;经过多代迭代不断提升自然语言理解和生成能力。 在过去的一年中&#xff0c;OpenAI先后发布了GPT-4、GPT‑4.1及多种mini版本&#xff0c;为不同使用场景提供灵活选择。​ 随着用户需求向更高效、更精准的推理和视觉…

MATLAB 控制系统设计与仿真 - 36

鲁棒工具箱定义了个新的对象类ureal,可以定义在某个区间内可变的变量。 函数的调用格式为&#xff1a; p ureal(name,nominalvalue) % name为变量名,nominalValue为标称值&#xff0c;默认变化值为/-1 p ureal(name,nominalvalue,PlusMinus,plusminus) p ureal(name,nomin…

Spring数据访问全解析:ORM整合与JDBC高效实践

目录 一、Spring ORM集成深度剖析 &#x1f31f; ORM模块架构设计 核心集成特性&#xff1a; 整合MyBatis示例配置&#xff1a; 二、Spring JDBC高效实践指南 &#x1f31f; 传统JDBC vs Spring JDBC对比 &#x1f31f; JdbcTemplate核心操作示例 批量操作优化&#xf…

【HCIA】使用Access port实现简易的VLAN间通信

前言 当我们拥有一台三层交换机与两个vlan&#xff0c;我们可以使用简易的Vlanif配置实现VLAN间通信。 文章目录 前言1. 拓扑图2. 配置交换机3. 配置PC1与PC2的网络4. port link-type后记修改记录 1. 拓扑图 2. 配置交换机 <Huawei>system-view [Huawei]undo info-cent…