Java线程池详解,内含实战演练~

news2025/4/28 13:29:34

 本文是向大家介绍线程池的使用和一些注意事项,它能够实现高并发下快速处理业务,能够帮助开发人员深入理解线程池的价值。


1. 简介

线程池是使用池化技术管理和使用线程的一种机制。池化技术:提前准备一些资源,在需要时可以重复使用使用提前准备的资源。常见的有内存池、数据库连接池等。

2. 参数说明

  1. 需要如下参数:

corePoolSize:核心线程数。默认情况下,核心线程会一直存活,但是当将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。

maximumPoolSize:线程池所能容纳的最大线程数。当活跃线程数达到该数值后,后续的新任务将会阻塞。

keepAliveTime:线程闲置超时时长。如果超过该时长,非核心线程就会被回收。

unit:指定 keepAliveTime 参数的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。

workQueue:任务队列。通过线程池的 execute() 方法提交的 Runnable 对象将存储在该参数中。其采用阻塞队列实现。

threadFactory(可选):线程工厂。用于指定为线程池创建新线程的方式。

handler(可选):拒绝策略。当达到最大线程数时需要执行的饱和策略。

  1. 参数配置异常
if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||
    keepAliveTime < 0){
    throw new IllegalArgumentException();
}            

3. 使用顺序

核心线程满->任务队列满->最大线程满->拒绝处理

一个线程池所能承载最大线程量:任务队列大小+最大线程数

4. 默认线程工厂

Executors 框架已经为我们实现了默认的线程池:

线程池

最大线程数

任务队列

应用场景

FixedThreadPool

自定义

LinkedBlockingQueue

控制线程最大并发数,cpu比较平稳

ScheduledThreadPool

Integer.MAX_VALUE

DelayedWorkQueue

执行定时或周期性的任务

CachedThreadPool

Integer.MAX_VALUE

SynchronousQueue

执行大量、耗时少的任务

SingleThreadExecutor

1

LinkedBlockingQueue

单线程的线程池,保证执行顺序

总结:

  1. FixedThreadPool SingleThreadExecutor:主要问题是堆积的请求处理队列均采用 LinkedBlockingQueue,而LinkedBlockingQueue未指定容量,默认大小是Integer.MAX_VALUE,可能会耗费非常大的内存导致 OOM。任务队列无界时,设置最大线程数是没有意义的。
  2. CachedThreadPool ScheduledThreadPool:主要问题是线程最大数是 Integer.MAX_VALUE,可能会创建数量非常多的线程导致 OOM。
  3. Executors 的 4 个功能线程池虽然方便,但不建议使用,而是建议直接通过使用 ThreadPoolExecutor 的方式,规避资源耗尽的风险

5. 正确打开方式

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
    //核心线程数
    1,
    //最大线程数
    1,
    //超时时间
    1L,
    //时间单位
    TimeUnit.MILLISECONDS,
    //任务队列
    new LinkedBlockingDeque<Runnable>(1),
    //线程工厂
    new MyThreadFactory(),
    //拒绝策略
    new MyThreadRunsPolicy());
  1. 指定最大线程数
  2. 任务队列指定大小
  3. 线程工厂自定义

参考DefaultThreadFactory,自定义MyThreadFactory只修改了名字前缀,方便查询日志

public class MyThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    MyThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                Thread.currentThread().getThreadGroup();
         //此处只修改了一下名字前缀      
        namePrefix = "业务1-" +
                poolNumber.getAndIncrement() +
                "-thread-";
        System.out.println("--->"+namePrefix);
    }
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                namePrefix + threadNumber.getAndIncrement(),
                0);
        if (t.isDaemon()){
            t.setDaemon(false);
        }
        if (t.getPriority() != Thread.NORM_PRIORITY){
            t.setPriority(Thread.NORM_PRIORITY);
        }
        return t;
    }
}
  1. 自定义拒绝策略
public class MyThreadRunsPolicy implements RejectedExecutionHandler {
        MyThreadRunsPolicy() {
            super();
        }

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            try {
                final Thread t = new Thread(r, "Temporary task executor");
                t.start();
            } catch (Throwable e) {
                throw new RejectedExecutionException("Failed to start a new thread", e);
            }
        }
    }

Executors 框架已经为我们实现了 4 种拒绝策略:

  1. AbortPolicy(默认):丢弃任务并抛出 RejectedExecutionException 异常。
  2. CallerRunsPolicy:由调用线程处理该任务,
  3. DiscardPolicy:丢弃任务,但是不抛出异常。
  4. DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。

6. springboot集成线程池

  1. 全局线程池配置
@Configuration
@EnableAsync // 利用@EnableAsync注解开启异步任务支持
public class CustomMultiThreadingConfig {
    @Bean("threadPoolTaskExecutor")
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        // 核心线程数
        taskExecutor.setCorePoolSize(10);
        // 最大线程数
        taskExecutor.setMaxPoolSize(20);
        //配置队列大小
        taskExecutor.setQueueCapacity(10);
        // 配置线程池前缀
        taskExecutor.setThreadNamePrefix("async-service-");
        // 配置拒绝策略
        taskExecutor.setRejectedExecutionHandler(new MyThreadRunsPolicy());
        // 数据初始化
        taskExecutor.initialize();
        return taskExecutor;
    }

    private static final class MyThreadRunsPolicy implements RejectedExecutionHandler {
        MyThreadRunsPolicy() {
            super();
        }

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            try {
                final Thread t = new Thread(r, "Temporary task executor");
                t.start();
            } catch (Throwable e) {
                throw new RejectedExecutionException("Failed to start a new thread", e);
            }
        }
    }
}
  1. 待线程池执行任务添加@Async("threadPoolTaskExecutor")
@Component
public class AsyncSubTaskExecutorServiceImpl implements AsyncSubTaskExecutorService {
    @Async("threadPoolTaskExecutor")
    @Override
    public void extracted() {
        
    }
}

注意:异步方法A调用异步方法B时,A和B不能在同一类中,否则无效

7. 浅谈设置线程池大小

7.1 计算线程池最优大小的公式:

W/C 称为阻塞系数,对于CPU密集型任务阻塞系数为0,cpu核的数量就是线程数,拥有更多的线程数也是用处不大的。也可以得到“线程等待时间所占比例越高,需要越多线程”。

7.1.1 获取核数

16个CPU,1核,所以有16个逻辑CPU

7.1.2 获取等待输入输出的CPU时间百分比

"top"命令查看cup详情

按“1”键查看所有cpu

wa 等待输入输出的CPU时间百分比,CPU等待磁盘IO操作的时间

us 用户空间占用CPU百分比,比如shell程序、各种语言的编译器、数据库应用、web服务器和各种桌面应用等;

sy 内核空间占用CPU百分比,系统资源都是由Linux内核处理,比如分配一些内存、或是执行IO操作、再或者是去创建一个子进程。

7.2 实战:reconciliationweb结算同步任务线程数调试

1. 根据并发高低和任务执行时间来估算线程数

并发

任务执行时间

业务类型

估算

cpu核数+1,减少线程上下文切换

使用中间件等加速执行时间

IO密集型:

文件传输,网络请求等,cpu需等待结果后执行下一步

cpu核数*2+1

CPU密集型:

递归计算等

cpu核数+1

cpu核数+1

通过linux命令查看reconciliationweb服务核数为16,结算同步业务仅商务人员操作,并发低,但数据量大,数据量达400万,调用支付宝接口执行时间长,属于IO密集型,那么线程数起点可以配置33来调试。

2. 查看reconciliationweb服务分配核数

查看服务分配2核cpu,8g内存;

3. k8s上查看cpu使用情况

通过不断调试核数,来查看cpu使用的变化趋势,在满足平均cpu使用率不超过80%的情况下找到接近最优解的值;

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

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

相关文章

200颗卫星!武大“东方慧眼”星座项目发布

本文转自武汉大学官微 4月24日&#xff0c;是“中国航天日”&#xff0c;“东方慧眼”智能遥感星座项目在武汉大学宣布正式启动。 针对当前我国卫星遥感存在“成本高、效率低、不稳定、应用少”等诸多问题&#xff0c;“东方慧眼”智能遥感卫星星座计划通过卫星星座组网观测、…

【环境配置】Window上Git clone 如何提高速度

步骤一&#xff1a;得到ip 在下列网站上 https://www.ipaddress.com/ 分别搜索&#xff1a; github.global.ssl.fastly.netgithub.com然后记录得到的IP地址 步骤二&#xff1a; 修改host 在Windows中&#xff0c;先进入&#xff1a;C:\Windows\System32\drivers\etc 目录 …

MySQL: 数据类型之整数型、浮点数、时间日期

目录 前言&#xff1a; 数据类型&#xff1a; 整数型&#xff1a; 浮点数与定点数&#xff1a; 浮点数&#xff1a; 定点数&#xff1a; 日期与时间&#xff1a; DATATIME: DATE&#xff1a; TIMESTAMP: ​编辑 YEAR: TIME: 前言&#xff1a; 前面的几篇写了如何创…

css-设置单行文本溢出省略号,使用overflow:hidden属性之后的出现的问题几解决办法。

1 设置单行文本溢出后出现省略号 必要&#xff1a;需要设置固定宽度&#xff0c;不允许换行 width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; 2 设置N行文本…

每天一道大厂SQL题【Day24】华泰证券真题实战(六)

文章目录 每天一道大厂SQL题【Day24】华泰证券真题实战(六)每日语录第24题&#xff1a;需求列表 思路分析答案获取加技术群讨论文末SQL小技巧 后记 每天一道大厂SQL题【Day24】华泰证券真题实战(六) 大家好&#xff0c;我是Maynor。相信大家和我一样&#xff0c;都有一个大厂梦…

如何生成以及校验token

1️⃣ What is token&#xff1f; token是令牌的意思&#xff0c;作用就像“通关令牌”一样&#xff0c;持有token的请求会被“放行”&#xff0c;不持有token的请求可以被拦截&#xff08;可以设置白名单使不被拦截&#xff0c;例如登陆请求&#xff09;。 token是由…

Dockere-Compose迁移Gitea部署

Dockere-Compose迁移Gitea部署 ps: 江湖不是打打杀杀&#xff0c;江湖是人情事故。 解释&#xff1a; Gitea&#xff1a;类似于Git的代码版本管理工具。Docker&#xff1a;Docker-Compose&#xff1a; Docker命令&#xff1a; 查看镜像&#xff1a;docker images 删除镜像…

web自动化测试入门篇07 ——— 用例编写技巧

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

idea中导入spring源码错误during working with external system: java.lang.AssertionError

标题:idea中导入spring源码错误during working with external system: java.lang.AssertionError 1.Spring源码编译环境 spring 5.3.1 JDK环境:1.8 Spring版本:5.3.1版本 开发工具:IntelliJ IDEA 2019.10 编译工具:Gradle-6.4-bin 操作系统:windows 10 注&#xff1a; sprin…

分支和循环语句(2)

文章目录 3.2 for循环3.2.1 for语句的语法3.2.2 for循环中的break和continue3.2.3 for语句的循环控制变量3.2.4 一些for循环的变种3.2.5 一道笔试题 3.3 do while循环3.3.1 do语句的语法3.3.2 do语句的特点3.3.3 do while循环中的break和continue 3.4 练习3.4.1 计算 n的阶乘3.…

数据可视化工具汇总:数字孪生产品的得力助手

数字孪生技术是一项快速发展的新兴技术&#xff0c;已经在许多领域得到广泛应用。数字孪生技术不仅可以提供完整的虚拟模型&#xff0c;还可以模拟物理系统的行为。在数字孪生技术的推动下&#xff0c;越来越多的数字孪生产品开始涌现出来&#xff0c;为不同的领域提供支持和解…

2023年保理产品研究报告

第一章 行业概况 1.1 概述 保理&#xff08;Factoring&#xff09;&#xff0c;全称保付代理&#xff0c;又称托收保付&#xff0c;是一种通过将企业的应收账款出售给专业金融机构&#xff08;保理公司&#xff09;来获得资金的融资方式。保理业务通常包括两种类型&#xff1…

数据治理:解决一物多码,多品牌食品集团主数据管理实践

浙江顶誉集团是一家知名的食品加工集团&#xff0c;拥有久久丫、留夫鸭等多个品牌。一直重视企业信息化建设&#xff0c;更是把数字化作为集团的一大发展方向&#xff0c;立志不断加大数字化投入和建设&#xff0c;成为一个数字化的企业。因此&#xff0c;该企业与亿信华辰合作…

如何通过FAQ页面减轻客户支持压力,提高工作效率?

作为现代企业不可或缺的一部分&#xff0c;客户支持服务是为客户提供解决方案、回答问题和解决技术难题的关键部分。无论是产品管理还是销售环节&#xff0c;客户支持都是重要的一环。然而&#xff0c;有效地处理技术支持问题和客户请求并不容易。卓越的客户支持需要组织结构&a…

CCFC22102B 时钟分析

CCFC2012BC基于国芯科技自主PowerPC架构C*Core CPU内核研发&#xff0c;是一款汽车电子中高端车身及网关控制芯片&#xff0c;可广泛应用于车身控制和网关以及新能源车的整车控制&#xff0c;实现对国外产品如NXP&#xff08;恩智浦&#xff09;MPC5604BC、MPC5607B系列以及ST的…

Seurat -- variable features select

brief seurat提供的教学里面包含了Standard pre-processing workflow,workflow包括QC&#xff0c;normalization&#xff0c;scale data &#xff0c;detection of highly variable features。其中 normalization就有蛮多方法的&#xff0c;seurat自己就提供了两种&#xff0c…

OpenGL入门教程之 坐标系统

原文文章 原文链接  本文仅对有代码的地方做讨论。 投影矩阵 创建一个正射投影矩阵 glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);第一二个参数指定了平截头体的左右坐标&#xff0c;第三四个参数指定了平截头体的底部和上部&#xff0c;第五六个参数指定了近平面…

idea基于docker插件部署docker服务

IDEA开发完项目&#xff0c;直接部署至docker上镜像运行&#xff0c;接下来开始体验吧 注意&#xff1a;假定您的项目开发完了&#xff0c;假定你准备好了docker服务哈 没安装docker的来抄作业&#xff08;docker的安装&#xff09; 我的docker所在宿主机的内网ip&#xff1a;1…

银行卡识别OCR:解放金融业务处理效率的黑科技

引言 随着移动支付和电子商务的快速发展&#xff0c;人们越来越依赖银行卡进行交易。而银行卡信息的识别和处理也变得越来越重要。传统的手动输入银行卡信息方式效率低下且容易出错&#xff0c;而采用银行卡识别OCR 技术可以实现快速自动识别银行卡信息&#xff0c;极大地提高…

git把一个分支上的某次修改同步到另一个分支上,并解决git cherry-pick 冲突

背景 我们在工作中经常会碰到好几个同事共同在一个分支上开发&#xff0c;一个项目同时会有好几个分支&#xff0c;我们在feature上开发的功能时&#xff0c;有可能某个需求需要提前发布&#xff0c;这个时候我们已经在feature A上开发完成&#xff0c;但是需要在master上发布…