【推荐】领导说Java线程池都用不好,明天不要来了?

news2025/7/15 3:13:18

引言

工作中难免会遇到各种并发场景,笔者先后经历的公司中,很多同事或多或少都用到过Java线程池来实现并发处理。

但线程池用的好的,却没几个。笔者也曾排查过线上问题,有几次,都是因为线程泄漏,导致出现无法创建更多线程,甚至JVM垃圾回收一直无法成功,最终引发故障。

今天给大家分享一下,实际工作中,线程池应该如何用,才是最正确的。

一、线程池使用几个重要原则

原则1:禁止在请求到达,执行方法中创建线程池。

释义:请求并发高的时候,一个请求创建一个线程池,服务器线程资源会被瞬间打垮。线程池的创建,是一个很重的操作,且容易出现线程泄漏。参看本文【附1:线程池泄漏案例】

原则2:线程池创建,尽量使用Spring 容器来管理其生命周期,当JVM关闭时,同步关闭线程池。

释义:防止线程池hold住JVM进程,导致Spring 容器已经关闭,但java 进程还在,造成应用假活现象。

原则3:线程池创建,应该使用自定义线程创建工厂类,定制线程创建名称。

释义:使用自定义创建工厂类,定制线程名称生成规则,可方便线上排查问题时,诊断线程池的运行情况。

原则4:业务并发不高的场景,禁止擅自创建线程池,应该考虑复用现有业务线程池。

释义:并发不高的场景,通常情况,不过是想利用并行处理,或者异步处理的机制。非必要,不应该创建更多线程池。否则线程池会出现滥用情况,越来越不可控。

二、自定义线程池创建示例

集中创建,便于集中管理,Spring 容器关闭时,自动将线程池也关闭掉。

@Configuration
@EnableAsync
public class BizExcutorConfig {
    private static final int defaultThreadNum = Runtime.getRuntime().availableProcessors() * 2;

    public final static List<ThreadPoolExecutor> DEMO_EXECUTORS = Lists.newArrayList();

    /**
     * 通用业务线程池-适合并发小的业务
     * 多个业务可以共用此线程池
     * */
    @Bean
    public ThreadPoolExecutor commonBizExecutor(){
        ThreadFactory threadFactory = new ThreadFactory() {
			// 自定义线程编号
            final AtomicInteger threadIndex = new AtomicInteger(1);
            @Override
            public Thread newThread(Runnable r) {
				// 自定义线程名称
                return new Thread(r, "commonBiz-" + threadIndex.getAndIncrement());
            }
        };
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
				// 自定义核心线程数
                defaultThreadNum,
				// 自定义最大线程数
                defaultThreadNum,
				// 自定义线程最大空闲时间				
                60,
				// 自定义线程最大空闲时间-单位
                TimeUnit.SECONDS,
				// 自定义线程繁忙时-缓存任务队列
                new ArrayBlockingQueue<>(100),
				// 自定义线程创建工厂类	
                threadFactory,
                // 自定义线程池繁忙时-拒绝策略-抛出异常由主线程处理
                new ThreadPoolExecutor.AbortPolicy()
        );
		// 加入线程池容器,JVM关闭时,自动销毁线程池
        DEMO_EXECUTORS.add(executor);
        return executor;
    }

    @PreDestroy
    public void closeThreadPool(){
        /** 线程池在JVM关闭后-应当自销毁 */
        for (ThreadPoolExecutor demoExecutor : DEMO_EXECUTORS) {
            demoExecutor.shutdown();
        }
    }
}

三、线程池泄漏案例

该案例存在的问题是:在main方法中创建线程池,方法已经按预期结束了,但是线程池仍然活跃。

public static void main(String[] args) throws IOException, IllegalAccessException, InterruptedException {
        final List<Integer> poolNo = Lists.newArrayList(1, 2, 3, 4, 5);
        for (int i = 0; i < 5; i++) {
            System.out.println("第 " + i + " 个线程池创建。");
            long start = System.currentTimeMillis();
            System.out.println(System.currentTimeMillis());
            final Integer seq = poolNo.get(i);
            ThreadFactory threadFactory = new ThreadFactory() {
                // 自定义线程编号
                final AtomicInteger threadIndex = new AtomicInteger(1);
                @Override
                public Thread newThread(Runnable r) {
                    // 自定义线程名称
                    return new Thread(r, "test" + seq + "-pool-" + threadIndex.getAndIncrement());
                }
            };
            ThreadPoolExecutor executor = new ThreadPoolExecutor(
                    // 自定义核心线程数
                    5,
                    // 自定义最大线程数
                    10,
                    // 自定义线程最大空闲时间
                    60,
                    // 自定义线程最大空闲时间-单位
                    TimeUnit.SECONDS,
                    // 自定义线程繁忙时-缓存任务队列
                    new ArrayBlockingQueue<>(100),
                    // 自定义线程创建工厂类
                    threadFactory,
                    // 自定义线程池繁忙时-拒绝策略-抛出异常由主线程处理
                    new ThreadPoolExecutor.AbortPolicy()
            );

            System.out.println(System.currentTimeMillis());
            System.out.println("耗时:" + (System.currentTimeMillis() - start));
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程提交任务1");
                }
            });
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程提交任务2");
                }
            });
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程提交任务3");
                }
            });
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程提交任务4");
                }
            });
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程提交任务5");
                }
            });
        }

        Thread.currentThread().sleep(360000000000000L);
    }

main方法创建线程池后,线程池没有任何引用,但是线程池一直存活,并不会被垃圾回收。

查看进程线程栈,可以清晰看到,当前线程池的线程并没有被回收。
在这里插入图片描述

最后,码字不易,如有不尽事宜之处,欢迎留言咨询,或微信搜索:java高手真经

联系作者,一起探讨交流。

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

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

相关文章

无主灯设计:点亮空间美学的现代之选

在这个追求个性化与舒适度并重的时代&#xff0c;家居照明已不再是简单的照明需求&#xff0c;它逐渐演变为营造空间氛围、彰显居住者品味的重要元素。无主灯设计&#xff0c;作为现代照明设计的一种流行趋势&#xff0c;以其灵活多变、层次丰富、光线柔和的特点&#xff0c;赢…

《黑神话:悟空》中的AI技术运用

2024年8 月 20 日&#xff0c;《黑神话&#xff1a;悟空》全球同步上线&#xff0c;作为首个国产 3A 游戏&#xff0c; 1. A lot of money&#xff1a;大量资金 2. A lot of resources&#xff1a;大量资源 3. A lot of time&#xff1a;大量时间 一、悟空中的AI技术 《‌黑…

oracle exadata x8-2 crs有报错PRVG-12885

PRVG-12885 处理办法&#xff1a; Output from # dcli -l root -g dbs_group ip addr list | grep ib shows that all MTU sizes are 65520 Output from # ifconfig -a shows that the MTU size for the loopback interface was 16436 临时办法&#xff1a; Set the mtu…

vue-admin-template pan版使用方法

新建文件夹&#xff0c;创建后端子文件夹&#xff0c;使用命令行创建django后端&#xff1a;django-admin startproject 后端名称 首先下载vue-admin-template-master文件&#xff0c;将其复制进项目的前端文件夹&#xff0c;在命令行中切换到前端目录&#xff0c;执行npm ins…

特征工程-数据处理

一、读取数据 import pandas as pd import numpy as npdf pd.read_csv(E:/workspace/dataset/WA_Fn-UseC_-Telco-Customer-Churn.csv) df.head()字段解释&#xff1a; 二、数据质量探索 1、去重分析 df1 df.copy()# 判断是否存在重复 df1[customerID].nunique() df1.shape[…

性能飞跃!18种大模型指令调优技巧大放送,打造更强LLM!

指令调优&#xff08;IT&#xff09;&#xff0c;一种针对大型语言模型&#xff08;LLMs&#xff09;的训练方法&#xff0c;是提高大型语言模型能力和可控性的关键技术。该方法的核心目标是使LLM具备遵循自然语言指令并完成现实世界任务的能力。它弥补了LLM的下一个单词预测目…

[Meachines] [Easy] BoardLight Dolibarr17.0.0-RCE+Enlightenment v0.25.3权限提升

信息收集 IP AddressOpening Ports10.10.11.11TCP:22,80 $ nmap -p- 10.10.11.11 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 06:2…

【软件使用-MEGA】报错及解决方法

报错1&#xff1a;Error: MEGA has detected duplicate taxa labels. (in line 370) **************************************************************************** ; Please note the following important messages: ; **********************************…

怎么写文献综述?文献综述方法和工具推荐!

文献综述是每个科研人绕不过的坎&#xff0c;其实文献综述简单说就是对你自己研究主题之前的研究的一个完整的概括&#xff0c;这个完整的概括主要是来展示目前已有的一些观点和未来可能可以在这个主题之下能够研究的一些创新点&#xff0c;用很多文献来支撑你自己的研究主题。…

Java11 文件操作和io流

文件操作和IO流 文件操作和IO流磁盘操作File类创建file对象文件操作获取文件信息判断文件删除文件创建文件 Files工具类字符操作字节操作遍历目录&#xff08;非递归&#xff09; IO流字节操作&#xff08;字节流&#xff09;输出流&#xff1a;InputStream&#xff08;读&…

C++学习笔记——菲波那契数

一、题目描述 二、代码 #include <iostream> using namespace std;int main() {int k0;cin >> k;int a[k];a[0]1;a[1]1;for(int i2;i<k;i){a[i] a[i-1] a[i-2] ;}cout << a[k-1];return 0; }

VBA技术资料MF193:获取右键菜单的名称及ID

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

合宙Air700EAQ硬件设计手册——射频接口、电气特与规格

合宙Air700EAQ是一款基于移芯EC716E平台设计的LTE Cat 1无线通信模组。 支持亚洲FDD-LTE的4G远距离无线传 输技术。 以极小封装&#xff0c;极高性价比&#xff0c;满足IoT行业的数传应用需求。 例如共享应用场景&#xff0c;定位器场景&#xff0c;DTU数 传场景等。 本文我…

中仕公考怎么样?考公怎么看我的专业能不能报?

正在国考备考的考生们注意看了&#xff0c;怎么看自己的专业是否能报?中仕为大家讲解一下! 在公务员考试中&#xff0c;不同的专业可选择的岗位不同&#xff0c;根据岗位的多少又分为&#xff1a;热门专业和冷门专业&#xff0c;那些专业是热门专业? 考公热门专业&#xff…

Java 工厂模式的使用,零基础教程,上手即会

工厂模式&#xff08;Factory Pattern&#xff09;是一种常用的创建型设计模式&#xff0c;它提供了一种创建对象的最佳方式。在工厂模式中&#xff0c;我们在创建对象时不会对客户端暴露创建逻辑&#xff0c;并且是通过使用一个共同的接口来指向新创建的对象。&#xff08;常用…

splunk Enterprise 的HTTP收集器-windows

1.创建HTTP收集器 2.使用HTTP收集器 然后打开全局设置&#xff1a;把ssl给去掉&#xff0c;点保存&#xff08;保存之后&#xff0c;可以看到这些状态全部都是已启用了&#xff09;&#xff1a; 3.测试&#xff1a; curl --location --request POST http://192.168.11.131:808…

为什么已经设置了.gitignore文件,但某些需要被忽略的文件仍然显示?如何解决.gitignore无法忽略文件?

问题描述&#xff1a; 某个同事&#xff0c;不小心把编译文件夹&#xff08;这两个文件夹【uni_modules 和unpackage】&#xff09;提交到了远程仓库里。导致其他人提交的时候提示了冲突。因为每个人编译出来的文件都不一样。 然后我们在.gitignore文件设置了排除这两个文件夹…

5步打造安顺旅游数据可视化分析系统——Python Django + Vue 技术

&#x1f393; 作者&#xff1a;计算机毕设小月哥 | 软件开发专家 &#x1f5a5;️ 简介&#xff1a;8年计算机软件程序开发经验。精通Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等技术栈。 &#x1f6e0;️ 专业服务 &#x1f6e0;️ 需求定制化开发源码提…

Modbus rtu的通信(做主站)

Modbus rtu的通信&#xff08;做主站&#xff09; 首先进入“设备视图”添加通讯模块RS422/RS485通讯模块&#xff0c;点击通讯接口&#xff0c;配置modbus的参数&#xff0c;常规→端口组态&#xff0c;选择“半双工&#xff08;RS-485&#xff09;2线制模式”&#xff0c;波特…

一个案例讲清楚利用电商API数据分析的逻辑

01 分析思路 通过经营整体数据、客群、商品3个方向。 目前整体的销售走势如何&#xff1f;都通过哪些渠道进店&#xff1f;整店转化率怎么样&#xff1f;一周内哪天最活跃&#xff1f;客群转化和留存如何&#xff1f;哪些品类和商品为主要贡献&#xff1f; 02 数据定义与处…