ThreadPool-线程池使用及原理

1. 线程池使用方式

示例代码:

// 一池N线程
Executors.newFixedThreadPool(int)
// 一个任务一个任务执行,一池一线程
Executors.newSingleThreadExecutorO
// 线程池根据需求创建线程,可扩容,遇强则强
Executors.newCachedThreadPool()
// 自定义线程池方式
new ThreadPoolExecutor(...)

注:一般在工作中都是根据业务场景进行自定义线程池,进行使用;
自定义线程池方法;详见后面章节:自定义线程池

2. 线程池底层工作原理

a. 线程池参数:

线程池,具有多个参数:具有各自的含义:

七参数:

  • corePoolSize:核心线程数,一直保持活跃状态的线程
  • maximumPoolSize:最大线程数,线程池能容纳的最大线程数量
  • keepAliveTime:空闲线程存活时间,非核心线程的空闲存活时间
  • unit:存活的时间单位,非核心线程的空闲存活时间单位
  • workQueue:存放未执行任务的队列
  • threadFactory:线程工厂,创建线程的工厂类
  • handler:拒绝策略,队列满了和达到最大线程数后的拒绝策略

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

b. 线程池的拒绝策略

AbortPolicy:默认,直接抛出RejectedExcutionException异常,阻止系统正常运行
CallerRunsPolicy:该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者
DiscardPolicy:直接丢弃任务,不予任何处理也不抛出异常,如果允许任务丢失,这是一种好方案
DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务

c. 线程池底层工作原理

  1. 在创建了线程池后,如果设置了核心线程数(corePoolSize),则线程池中的线程数会先创建相应数量的核心线程。如果没有任务到达,这些核心线程会保持活动状态。

  2. 当调用execute()方法添加一个请求任务时,线程池会根据以下判断来决定任务的执行方式:

    • 如果正在运行的线程数量小于核心线程数(corePoolSize),则会立即使用核心线程来执行任务。
    • 如果正在运行的线程数量大于或等于核心线程数,但任务队列未满,则任务会被放入队列中等待执行。
    • 如果队列已满且正在运行的线程数量小于最大线程数(maximumPoolSize),则会创建非核心线程来执行任务。
      • 这里需要注意,是先执行新的任务,队列里的任务不会执行,详见:5. 注意事项
    • 如果队列已满且正在运行的线程数量已达到最大线程数,且拒绝策略允许,那么线程池会启动拒绝策略来处理新任务。
  3. 当一个线程完成任务时,它会从队列中取下一个任务来执行,或者在没有任务的情况下进入等待状态。

  4. 当一个线程空闲时间超过设定的keepAliveTime时,线程池会根据以下判断来决定线程的命运:

    • 如果当前运行的线程数大于核心线程数(corePoolSize),则空闲线程会被终止。
    • 线程池的所有任务完成后,它最终会收缩到核心线程数的大小。
  5. 注意事项:

    在Java中java.util.concurrent.ThreadPoolExecutor线程池的默认行为是,当任务队列已满且再来一个新任务时,创建的新线程会被用来执行新来的任务而不是队列里已有的任务。

  6. 线程工作原理示意图:

    • 在这里插入图片描述

3. 自定义线程池

a. 介绍:

前面提到过,一般在工作中都是根据业务场景进行自定义线程池;西面是阿里巴巴开发手册的说明;
在这里插入图片描述

b. 实现:

实现代码如下:

import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.concurrent.*;/*** @author xxx* @version 1.0* @date xxx*/@Configuration
public class ThreadPoolExecutorConfig {@Beanpublic ThreadPoolExecutor threadPoolExecutor() {// 创建自定义线程池int corePoolSize = 2; // 核心线程数int maxPoolSize = 4; // 最大线程数long keepAliveTime = 10; // 线程空闲时间TimeUnit unit = TimeUnit.SECONDS; // 时间单位BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10); // 任务队列ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 线程工厂RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); // 拒绝策略// 创建ThreadPoolExecutor对象ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);return threadPool;}
}

4. 线程池参数的选择原则

仅供参考:具体的线程池参数,需要根据业务场景,进行合理的测试选择

一般原则:

在使用java.util.concurrent.ThreadPoolExecutor自定义线程池时,参数的设置需要根据具体的业务场景和需求进行调整。以下是一些常用的业务场景和设置原则:

  • 短时任务场景:
    corePoolSize (n+1):可以设置较小的值,例如CPU核心数加1。
    maximumPoolSize (2n):根据系统负载情况和任务的短时性来设置。通常可以设置为核心线程数的两倍或者根据系统资源进行调整。
    workQueue:可以选择容量较小的队列,例如SynchronousQueue,以避免任务积压。

  • 长时任务场景:
    corePoolSize:可以设置为一个相对较大的值,以确保有足够的线程处理任务。
    maximumPoolSize:根据系统负载和任务的长时性来设置。如果长时任务较多,可以将最大线程数设置得较大一些。
    keepAliveTime 和 TimeUnit:根据任务的处理时长和系统的响应时间来设置空闲线程的存活时间。

  • I/O密集型任务场景:
    corePoolSize(2n):可以设置为较大的值,以充分利用系统资源,加速I/O操作。
    maximumPoolSize:根据系统负载和I/O操作的并发数来设置,可以设置得比较大以应对高并发的情况。
    workQueue:可以选择一个适当大小的队列,以充分缓冲I/O任务,但不至于占用过多内存。

  • CPU密集型任务场景:
    corePoolSize:可以根据CPU核心数设置,以充分利用系统的多核处理能力。
    maximumPoolSize:可以设置得比较大,以应对突发的CPU密集型任务,但不要超过系统负载的承受范围。
    workQueue:选择一个合适大小的队列来缓冲任务,避免因任务积压导致性能下降。

设置原则:

要根据具体的业务需求和系统特点来选择参数。
要根据实际情况进行监控和调优,以确保线程池能够有效地处理任务并保持系统的稳定性和性能。
要平衡资源的利用和系统的响应能力,避免设置过大或过小的参数,导致资源浪费或性能问题。

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

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

相关文章

ssrf利用

ssrf利用 查找内网存活主机ip&#xff08;文件读取&#xff09; 使用file://协议 file:// 从文件系统中获取文件内容&#xff0c;格式为file://文件路径 file:///etc/passwd 读取文件passwd file:///etc/hosts 显示当前操作系统网卡的IP file:///…

CVPR`24 | FRESCO:高质量、连贯的Zero-shot视频转换新方案(北大南洋理工)

论文链接&#xff1a;https://arxiv.org/pdf/2403.12962.pdf 代码链接&#xff1a;https://github.com/williamyang1991/FRESCO 工程地址&#xff1a;https://www.mmlab-ntu.com/project/fresco/ 文本到图像扩散模型在图像领域的显著功效激发了人们对其在视频领域应用潜力的广…

Ansible-1

Ansible是一款自动化运维、批量管理服务器的工具&#xff0c;批量系统配置、程序部署、运行命令等功能。基于Python开发&#xff0c;基于ssh进行管理&#xff0c;不需要在被管理端安装任何软件。Ansible在管理远程主机的时候&#xff0c;只有是通过各种模块进行操作的。 需要关…

Web开发基本流程

Web是全球广域网&#xff0c;能够通过浏览器访问的网站。我们要访问网站&#xff0c;首先要在浏览器输入对应的域名。 浏览器也是一个程序&#xff0c;京东的网站也是一个程序&#xff0c;在京东那边电脑运行着&#xff0c;我们只是通过浏览器远程访问。京东的程序由三个部分组…

安卓玩机工具推荐----MTK芯片读写分区 备份分区 恢复分区 制作线刷包 从0开始 工具操作解析【三】

同类博文; 安卓玩机工具推荐----MTK芯片读写分区 备份分区 恢复分区 制作线刷包 工具操作解析 安卓玩机工具推荐----MTK芯片读写分区 备份分区 恢复分区 制作线刷包 工具操作解析【二】-CSDN博客 回顾以往 在以前的博文简单介绍了这款工具的rom制作全程。今天针对这款工具的…

【ESP32S3 Sense接入语音识别+MiniMax模型对话】

1. 前言 围绕ESP32S3 Sense接入语音识别MiniMax模型对话展开&#xff0c;首先串口输入“1”字符&#xff0c;随后麦克风采集2s声音数据&#xff0c;对接百度在线语音识别&#xff0c;将返回文本结果丢入MiniMax模型&#xff0c;进而返回第二次结果文本&#xff0c;实现语言对话…

软考高级架构师:边缘计算概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

【Java程序设计】【C00388】基于(JavaWeb)Springboot的校园竞赛管理系统(有论文)

Springboot的校园竞赛管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;博客…

[计算机效率] 文件预览工具:QuickLook

3.9 文件预览工具&#xff1a;QuickLook Quicklook是一款强大的文件预览工具&#xff0c;可以帮助用户快速浏览文件夹中的文件内容&#xff0c;而无需打开每个文件。 功能特点&#xff1a; 快速预览&#xff1a;Quicklook能够快速预览文件夹中的文件内容&#xff0c;包括文本…

【数据可视化】Echarts的高级功能

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1. ECharts的图表混搭及多图表联动1.1 ECharts的图表混搭1.2 ECharts的多图表联动 2. 动态切换主题及自定义ECharts主题2.1 ECharts 4.x/5.x中动态切换主题2.2 自定义ECharts主题 3. ECharts中的事件和行为3.1 EChart…

CentOS离线安装命令

一.引言 某些CentOS安装后默认是没有部分Linux命令的&#xff0c;比如netstat和lsof&#xff1a; 一般情况下我们可以通过yum install安装这些命令。但是在CentOS无法访问公网的时候&#xff08;比如CentOS服务器部署在学校、军工等无法访问外网的环境&#xff09;&#xff0c…

linux命令在线查询工具

您提供的链接是一个名为“Linux 命令在线查询工具 - 轻松查找命令信息”的在线工具页面。这个工具旨在帮助用户快速查找和了解Linux命令的详细信息&#xff0c;从而提高工作效率。 工具概述 Linux命令在线查询工具是一个便捷的资源&#xff0c;它允许用户通过简单的搜索功能来…