JavaDog程序狗
JavaDog程序狗
发布于 2025-05-15 / 11 阅读
0
0

【Java】女朋友都抱怨了,别再粗暴停止线程池啦!

前言

🍊缘由

Java线程池优雅停止:比分手还难的事,让我来全搞定

想象一下,关闭线程池就像和前任分手——既要干脆利落不留后患,又得顾及对方(任务)情绪别搞崩盘。你试过强行拔电源式关机吗?那可比"拉黑删除"还粗暴,轻则数据丢失资金对账差百万,重则文件损坏系统崩溃老板连夜报警!

🐣闪亮主角

大家好,我是JavaDog程序狗

今天手把手教你如何像处理渣男/渣女一样优雅地关线程池,保证项目不翻车

优雅停机三要素:温柔拒绝新客(shutdown)→耐心送走旧客(await)→强制清场备案(shutdownNow)

正文

🎯主要目标

1.线程池是什么

2.为什么要优雅停止线程池

3.线程池优雅停止的核心方法有哪些

4.实际业务场景中如何使用线程池优雅停止

5.代码示例展示线程池优雅停止

🍪目标讲解

一.线程池是什么?

1.白话理解

线程池就像是一个线程的“池子”,里面预先创建了一些线程。当有任务提交时,线程池会从池子中取出一个空闲的线程来执行任务。如果池子中没有空闲线程,任务就会被放到队列中等待。这样可以避免频繁地创建和销毁线程,提高系统的性能。

线程池就像你的恋爱对象:

  • 核心线程:天天粘着你的“正经男友/女友”

  • 最大线程:节日突击出现的“临时男友/女友”

  • 任务队列:你们没吃完的火锅,总得吃完再散!

  • 拒绝策略:TA突然说“分手吧”,但你还有99个约会没处理……

2.官方解释

官网解释:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html

在Java中,线程池是通过ExecutorService接口及其实现类来实现的。常见的线程池实现类有ThreadPoolExecutorScheduledThreadPoolExecutor等。


二.为什么要优雅停止线程池?

想象一下,你正在玩一款游戏,突然游戏崩溃了,你的进度还没保存,是不是很崩溃?线程池也是一样,如果不优雅地停止线程池,正在执行的任务可能会被强制中断,导致数据丢失或者系统出现异常。

1.避免数据丢失

如果线程正在处理一些重要的数据,突然被中断,这些数据可能就会丢失。比如,一个线程正在将数据写入数据库,还没写完就被中断了,那么数据库中的数据就可能不完整。

2.保证系统稳定性

不优雅地停止线程池可能会导致系统出现一些不可预知的问题。比如,线程池中的线程可能会持有一些资源,如文件句柄、网络连接等,如果不优雅地停止,这些资源可能无法被正确释放,从而导致系统资源泄漏。


三.线程池优雅停止的核心方法有哪些?

1.shutdown()方法

shutdown()方法就像是给线程池里的工人们发了一个通知,告诉他们“大家把手上的活干完就可以下班啦”。调用这个方法后,线程池会拒绝接受新的任务,但是会继续执行已经提交的任务。

ExecutorService executorService = Executors.newFixedThreadPool(5);
// 提交一些任务
executorService.submit(() -> {
    // 任务逻辑
});
// 调用shutdown()方法
executorService.shutdown();
  • 优点:给线程池发分手短信:“以后不联系了,但今天的约会我全认!”

  • 缺点:如果TA是妈宝男/妈宝女,死活赖着不走怎么办?

2.shutdownNow()方法

shutdownNow()方法就像是给线程池里的工人们下了一道紧急命令,“别干了,马上都给我下班”。调用这个方法后,线程池会尝试中断正在执行的任务,并返回那些还未开始执行的任务列表。

ExecutorService executorService = Executors.newFixedThreadPool(5);
// 提交一些任务
executorService.submit(() -> {
    // 任务逻辑
});
// 调用shutdownNow()方法
List<Runnable> tasks = executorService.shutdownNow();
  • 优点:直接拉黑线程池,任务列表清空比删微信更快!

  • 缺点:未完成任务直接变成“幽灵订单”,数据库连接池连夜报警!

3.awaitTermination()方法

awaitTermination()方法就像是在门口等着工人们下班。它会阻塞当前线程,直到线程池中的所有任务都执行完毕或者达到指定的超时时间。

ExecutorService executorService = Executors.newFixedThreadPool(5);
// 提交一些任务
executorService.submit(() -> {
    // 任务逻辑
});
// 调用shutdown()方法
executorService.shutdown();
try {
    // 等待线程池中的任务执行完毕,最多等待10秒
    if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
        // 如果超时还没执行完,调用shutdownNow()方法强制停止
        executorService.shutdownNow();
    }
} catch (InterruptedException e) {
    // 处理中断异常
    executorService.shutdownNow();
}

四.实际业务场景中如何使用线程池优雅停止?

1.电商系统中的订单处理

在电商系统中,当用户下单后,系统会有一系列的任务需要处理,如扣减库存、生成物流信息等。这些任务可以使用线程池来并行处理。当系统要关闭时,就需要优雅地停止线程池,以确保所有的订单任务都能正确处理完毕。

ExecutorService executorService = Executors.newFixedThreadPool(5);
// 模拟用户下单
executorService.submit(() -> {
    // 扣减库存
});
executorService.submit(() -> {
    // 生成物流信息
});
// 系统关闭时,优雅停止线程池
executorService.shutdown();
try {
    if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
        executorService.shutdownNow();
    }
} catch (InterruptedException e) {
    executorService.shutdownNow();
}

2.数据分析系统中的数据处理

在数据分析系统中,需要对大量的数据进行处理和分析。这些任务可以使用线程池来提高处理效率。当数据分析任务完成后,需要优雅地停止线程池,以释放系统资源。

ExecutorService executorService = Executors.newFixedThreadPool(5);
// 提交数据处理任务
executorService.submit(() -> {
    // 数据处理逻辑
});
// 任务完成后,优雅停止线程池
executorService.shutdown();
try {
    if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
        executorService.shutdownNow();
    }
} catch (InterruptedException e) {
    executorService.shutdownNow();
}

五.代码示例展示线程池优雅停止

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadPoolGracefulShutdownExample {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        // 提交一些任务
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executorService.submit(() -> {
                try {
                    System.out.println("Task " + taskId + " is running.");
                    Thread.sleep(1000);
                    System.out.println("Task " + taskId + " is completed.");
                } catch (InterruptedException e) {
                    System.out.println("Task " + taskId + " is interrupted.");
                }
            });
        }

        // 调用shutdown()方法
        executorService.shutdown();

        try {
            // 等待线程池中的任务执行完毕,最多等待10秒
            if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
                // 如果超时还没执行完,调用shutdownNow()方法强制停止
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            // 处理中断异常
            executorService.shutdownNow();
        }

        System.out.println("ThreadPool is gracefully shutdown.");
    }
}

🍈猜你想问

如何与博主联系进行探讨

关注公众号【JavaDog程序狗】

公众号回复【入群】或者【加入】,便可成为【程序员学习交流摸鱼群】的一员,问题随便问,牛逼随便吹,目前群内已有超过380+个小伙伴啦!!!

2. 踩踩博主博客

javadog.net

里面有博主的私密联系方式呦 !,大家可以在里面留言,随意发挥,有问必答😘

🍯猜你喜欢

文章推荐

【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)

【规范】看看人家Git提交描述,那叫一个规矩

【项目实战】SpringBoot+uniapp+uview2打造H5+小程序+APP入门学习的聊天小项目

【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序

【模块分层】还不会SpringBoot项目模块分层?来这手把手教你!


评论