当前位置: 首页 > news >正文

线程未关闭导致资源泄漏

文章目录

  • 资源泄漏(线程未关闭)
    • 问题描述
    • 错误实现
    • 优化原理
    • 正确实现
    • 优化原理

资源泄漏(线程未关闭)

问题描述

应用程序启动时创建线程池处理任务,但未在应用关闭时正确关闭线程池。

  • 现象:
    • 应用重启时,残留的线程池线程仍在运行,占用内存和CPU资源。
    • 若线程池任务涉及外部资源(如数据库连接),可能导致资源耗尽或端口占用。

错误实现

  • 案例:未正确关闭线程池
public class ResourceLeakDemo {
    private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(
        2, 4, 60, TimeUnit.SECONDS,
        new LinkedBlockingQueue<>()
    );

    public static void main(String[] args) {
        executor.execute(() -> {
            while (true) {
                try {
                    System.out.println("执行任务中...");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        // 模拟应用关闭(未关闭线程池)
        System.out.println("主线程结束,但线程池仍在运行!");
    }
}
  • 结果
主线程结束,但线程池仍在运行!
执行任务中...
执行任务中...
...
  • 主线程结束后,线程池中的核心线程(非守护线程)会持续运行,导致JVM无法退出。

优化原理

调优方案与场景

调优目标

  • 确保线程池关闭:在应用退出时,优雅关闭线程池,释放所有资源。
  • 防止资源泄漏:终止所有线程,避免残留任务占用系统资源。

解决方案

  1. 显式调用 shutdown():在应用退出逻辑中手动关闭线程池。
  2. 注册JVM关闭钩子:确保即使非正常退出(如kill命令),也能触发线程池关闭。

正确实现

  • 调优后:
public class ResourceLeakFixedDemo {
    private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(
        2, 4, 60, TimeUnit.SECONDS,
        new LinkedBlockingQueue<>()
    );

    public static void main(String[] args) {
        // 注册JVM关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("JVM关闭钩子触发:关闭线程池...");
            shutdownThreadPool();
        }));

        executor.execute(() -> {
            while (true) {
                try {
                    System.out.println("执行任务中...");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("任务被中断,退出循环");
                    break;
                }
            }
        });

        // 模拟正常关闭(手动调用关闭逻辑)
        shutdownThreadPool();
        System.out.println("应用主线程结束");
    }

    private static void shutdownThreadPool() {
        executor.shutdown(); // 停止接受新任务,等待已有任务完成
        try {
            // 等待任务终止,最多10秒
            if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                executor.shutdownNow(); // 强制终止所有任务
                System.out.println("线程池强制关闭");
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
    }
}
  • 运行后:
执行任务中...
执行任务中...
JVM关闭钩子触发:关闭线程池...
执行任务中...
执行任务中...
执行任务中...
执行任务中...
线程池强制关闭
应用主线程结束
任务被中断,退出循环

优化原理

关键调优总结

1、注册关闭钩子

Runtime.getRuntime().addShutdownHook(new Thread(() -> shutdownThreadPool()));

2、优雅关闭线程池

  • shutdown():停止接受新任务,等待已有任务完成。
  • awaitTermination():设定超时时间,避免无限等待。
  • shutdownNow():超时后强制终止所有任务(向线程发送中断信号)。

3、任务响应中断

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    break; // 捕获中断信号,退出任务
}

4. 建议

  • 统一管理线程池生命周期:在应用启动/关闭时显式初始化和销毁线程池。
  • 监控线程池状态:记录活跃线程数、队列大小、拒绝任务数等指标。
  • 防御性编程:任务代码需正确处理中断,避免死循环。
http://www.dtcms.com/a/92007.html

相关文章:

  • Halcon找圆心
  • c++some
  • 如何为你的github开源项目选择合适的开源协议?
  • Go 1.24 新特性解析:泛型类型别名、弱指针与终结器改进
  • HTTP抓包Websocket抓包(Fiddler)
  • tar包部署rabbitMQ
  • 进阶版孟德尔随机化方法!遗传变异聚类+异质性检验,避免水平多效性带来的假阳性结果(PCMR)
  • C++ 命名空间
  • 【neo4j数据导出并在其他电脑导入】
  • SQL问题分析与诊断(8)——前提
  • 动态路由机制MoE专家库架构在多医疗AI专家协同会诊中的应用探析
  • 登山第二十一梯:点云补全——零样本、跨激光分布的“泥瓦匠”
  • 计算机二级(C语言)考试高频考点总汇(一)—— C语言通识、数据类型和运算符、位运算、进制转换、进制转换方法
  • LabVIEW柔性机械臂减振控制系统
  • LeetCode算法题(Go语言实现)_12
  • 今日行情明日机会——20250326
  • 微信小程序pdf预览
  • 基于ADMM无穷范数检测算法的MIMO通信系统信号检测MATLAB仿真,对比ML,MMSE,ZF以及LAMA
  • 华为OD机试A卷 - 快递业务站 计算快递主站点(C++ Java JavaScript Python )
  • 【图片识别Excel表格】批量将图片上的区域文字识别后保存为表格,基于WPF和阿里云的项目实战总结
  • Echarts使用
  • Chaos Mesh 混沌工程平台介绍、安装及使用指南
  • C++智能指针万字详细讲解(包含智能指针的模拟实现)
  • rANS:快速的渐进最优码
  • 【UTM】通用横轴墨卡托投影
  • WPF InkCanvas 控件详解
  • 树莓派超全系列文档--(7)RaspberryOS播放音频和视频
  • 等差数列公式推导
  • SynchronousQueue的不恰当使用,瞬时过载导致线程池任务被拒绝
  • 【hadoop】hadoop streaming