Spring Boot 中多线程工具类的配置与使用:基于 YAML 配置文件

news2025/2/21 11:28:25

文章目录

      • Spring Boot 中多线程工具类的配置与使用:基于 YAML 配置文件
      • 1. 为什么需要多线程工具类?
      • 2. 实现步骤
        • 2.1 添加依赖
        • 2.2 配置线程池参数
        • 2.3 创建配置类
        • 2.4 创建线程池工具类
        • 2.5 使用线程池工具类
        • 2.6 测试线程池工具类
      • 3. 配置文件的灵活性
      • 4. 总结


Spring Boot 中多线程工具类的配置与使用:基于 YAML 配置文件

在现代软件开发中,多线程编程是提高系统性能和并发处理能力的重要手段。Spring Boot 作为一款流行的 Java 开发框架,提供了强大的多线程支持。本文将详细介绍如何在 Spring Boot 中结合 YAML 配置文件,实现一个灵活、可配置的多线程工具类。


1. 为什么需要多线程工具类?

在多线程编程中,直接使用 ThreadExecutorService 可能会导致以下问题:

  • 资源浪费:频繁创建和销毁线程会消耗大量系统资源。
  • 难以管理:线程的生命周期和状态难以监控和维护。
  • 配置不灵活:线程池的参数(如核心线程数、队列容量等)硬编码在代码中,难以动态调整。

通过封装一个多线程工具类,并结合 YAML 配置文件,可以解决上述问题,使多线程编程更加高效和灵活。


2. 实现步骤

2.1 添加依赖

pom.xml 中添加 Spring Boot 的依赖:

<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <!-- Spring Boot Configuration Processor -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>
2.2 配置线程池参数

application.yml 中定义线程池的配置参数:

thread-pool:
  core-pool-size: 10 # 核心线程数
  max-pool-size: 20 # 最大线程数
  queue-capacity: 100 # 任务队列容量
  keep-alive-time: 60 # 线程空闲时间(秒)
  thread-name-prefix: "custom-thread-" # 线程名称前缀
2.3 创建配置类

通过 @ConfigurationProperties 注解将 YAML 文件中的配置映射到 Java 类中:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "thread-pool")
public class ThreadPoolProperties {
    private int corePoolSize;
    private int maxPoolSize;
    private int queueCapacity;
    private long keepAliveTime;
    private String threadNamePrefix;

    // Getters and Setters
    public int getCorePoolSize() {
        return corePoolSize;
    }

    public void setCorePoolSize(int corePoolSize) {
        this.corePoolSize = corePoolSize;
    }

    public int getMaxPoolSize() {
        return maxPoolSize;
    }

    public void setMaxPoolSize(int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
    }

    public int getQueueCapacity() {
        return queueCapacity;
    }

    public void setQueueCapacity(int queueCapacity) {
        this.queueCapacity = queueCapacity;
    }

    public long getKeepAliveTime() {
        return keepAliveTime;
    }

    public void setKeepAliveTime(long keepAliveTime) {
        this.keepAliveTime = keepAliveTime;
    }

    public String getThreadNamePrefix() {
        return threadNamePrefix;
    }

    public void setThreadNamePrefix(String threadNamePrefix) {
        this.threadNamePrefix = threadNamePrefix;
    }
}
2.4 创建线程池工具类

在工具类中注入 ThreadPoolProperties,并根据配置创建线程池:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.*;

@Component
public class ThreadPoolUtil {

    private ThreadPoolExecutor threadPool;

    @Autowired
    private ThreadPoolProperties threadPoolProperties;

    /**
     * 初始化线程池
     */
    @PostConstruct
    public void init() {
        threadPool = new ThreadPoolExecutor(
                threadPoolProperties.getCorePoolSize(),
                threadPoolProperties.getMaxPoolSize(),
                threadPoolProperties.getKeepAliveTime(),
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(threadPoolProperties.getQueueCapacity()),
                new ThreadFactory() {
                    private final AtomicInteger threadNumber = new AtomicInteger(1);

                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, threadPoolProperties.getThreadNamePrefix() + threadNumber.getAndIncrement());
                    }
                },
                new ThreadPoolExecutor.AbortPolicy() // 拒绝策略:直接抛出异常
        );
    }

    /**
     * 提交任务(Runnable)
     *
     * @param task 任务
     */
    public void execute(Runnable task) {
        threadPool.execute(task);
    }

    /**
     * 提交任务(Callable)
     *
     * @param task 任务
     * @param <T>  返回值类型
     * @return Future 对象
     */
    public <T> Future<T> submit(Callable<T> task) {
        return threadPool.submit(task);
    }

    /**
     * 关闭线程池(等待所有任务完成)
     */
    @PreDestroy
    public void shutdown() {
        if (threadPool != null) {
            threadPool.shutdown();
            try {
                if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
                    threadPool.shutdownNow();
                }
            } catch (InterruptedException e) {
                threadPool.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * 获取线程池状态
     *
     * @return 线程池状态信息
     */
    public String getThreadPoolStatus() {
        if (threadPool == null) {
            return "Thread pool is not initialized.";
        }
        return String.format(
                "Pool Status: [CorePoolSize: %d, ActiveThreads: %d, CompletedTasks: %d, QueueSize: %d]",
                threadPool.getCorePoolSize(),
                threadPool.getActiveCount(),
                threadPool.getCompletedTaskCount(),
                threadPool.getQueue().size()
        );
    }
}
2.5 使用线程池工具类

在业务代码中注入 ThreadPoolUtil,并提交任务:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class TaskService {

    @Autowired
    private ThreadPoolUtil threadPoolUtil;

    public void runTask() {
        // 提交 Runnable 任务
        threadPoolUtil.execute(() -> {
            System.out.println("Runnable task is running.");
        });

        // 提交 Callable 任务并获取结果
        Future<String> future = threadPoolUtil.submit(() -> {
            Thread.sleep(1000);
            return "Callable task result";
        });

        try {
            System.out.println("Callable task result: " + future.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        // 打印线程池状态
        System.out.println(threadPoolUtil.getThreadPoolStatus());
    }
}
2.6 测试线程池工具类

编写单元测试,验证线程池的功能:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ThreadPoolUtilTest {

    @Autowired
    private TaskService taskService;

    @Test
    public void testThreadPool() {
        taskService.runTask();
    }
}

3. 配置文件的灵活性

通过 application.yml 配置文件,可以灵活调整线程池的参数,而无需修改代码。例如:

  • 调整核心线程数:

    thread-pool:
      core-pool-size: 20
    
  • 调整任务队列容量:

    thread-pool:
      queue-capacity: 200
    
  • 调整线程名称前缀:

    thread-pool:
      thread-name-prefix: "app-thread-"
    

4. 总结

通过将线程池的配置参数提取到 application.yml 中,并结合 Spring Boot 的依赖注入机制,我们可以实现一个灵活、可配置的多线程工具类。这种方式不仅提高了代码的可维护性,还能根据实际需求动态调整线程池的行为,是 Spring Boot 项目中管理多线程任务的推荐做法。希望本文能帮助你更好地理解和应用 Spring Boot 中的多线程编程技术!

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

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

相关文章

【C++第二十章】红黑树

【C第二十章】红黑树 红黑树介绍&#x1f9d0; 红黑树是一种自平衡的二叉搜索树&#xff0c;通过颜色标记和特定规则保持树的平衡性&#xff0c;从而在动态插入、删除等操作中维持较高的效率。它的最长路径不会超过最短路径的两倍&#xff0c;它的查找效率比AVL树更慢(对于CPU…

如何修改Windows系统Ollama模型存储位置

默认情况下&#xff0c;Ollama 模型会存储在 C 盘用户目录下的 .ollama/models 文件夹中&#xff0c;这会占用大量 C 盘空间&#xff0c;增加C盘“爆红”的几率。所以&#xff0c;我们就需要修改Ollama的模型存储位置 Ollama提供了一个环境变量参数可以修改Ollama的默认存在位…

OpenAI ChatGPT在心理治疗领域展现超凡同理心,通过图灵测试挑战人类专家

近期&#xff0c;一项关于OpenAI ChatGPT在心理治疗领域的研究更是引起了广泛关注。据报道&#xff0c;ChatGPT已经成功通过了治疗师领域的图灵测试&#xff0c;其表现甚至在某些方面超越了人类治疗师&#xff0c;尤其是在展现同理心方面&#xff0c;这一发现无疑为AI在心理健康…

Netflix Ribbon:云端负载均衡利器

Netflix Ribbon&#xff1a;云端负载均衡利器 ribbon Ribbon is a Inter Process Communication (remote procedure calls) library with built in software load balancers. The primary usage model involves REST calls with various serialization scheme support. 项目地…

【Android】Android 悬浮窗开发 ( 动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

文章目录 一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后返回处理 二、悬浮窗 前台服务和通知1、前台服务 启动 悬浮窗 的必要性① 保持悬浮窗存活② 悬浮窗的要求③ 悬浮窗版本兼容 2、其它类型服务简介① 前台服务…

Python高级语法之jsonpathBeautifulSoup解析器

目录&#xff1a; 1、jsonPath的使用2、使用jsonpath解析淘票票网页3、BeautifulSoup解析器的使用4、BeautifulSoup层级选择器的使用 1、jsonPath的使用 2、使用jsonpath解析淘票票网页 3、BeautifulSoup解析器的使用 4、BeautifulSoup层级选择器的使用

工业安卓主板在智慧粮仓设备中发挥着至关重要的作用

工业安卓主板在智慧粮仓设备中发挥着至关重要的作用。以下是关于其作用的具体分析&#xff1a; 一、提供稳定可靠的运行平台 智慧粮仓设备需要长时间稳定运行&#xff0c;以实现对粮食储存环境的实时监测和精准控制。工业安卓主板采用高性能的处理器和大容量的存储空间&#…

ECMAScript6----var、let、const

ECMAScript6----var、let、const 1.var2.let3.const 1.var &#xff08;1&#xff09;在相同作用域下可重复声明 var a 20 var a 30 console.log(a) // 30&#xff08;2&#xff09;存在变量提升 console.log(a) // undefined var a 20&#xff08;3&#xff09;可修改声…

【ST-LINK未能被keil识别STM32 ST-LINK Utility出现“Can not connect to target】

针对各种品牌32MCU boot0拉高&#xff0c;boot1拉低进入系统存储器&#xff0c;对Flash先擦除在下载 针对STM32f103 通过32复位和stlink Utilit解决 https://blog.csdn.net/Donglutao/article/details/129086960 https://www.bilibili.com/video/BV1F94y1g7be/?spm_id_…

Android Http-server 本地 web 服务

时间&#xff1a;2025年2月16日 地点&#xff1a;深圳.前海湾 需求 我们都知道 webview 可加载 URI&#xff0c;他有自己的协议 scheme&#xff1a; content:// 标识数据由 Content Provider 管理file:// 本地文件 http:// 网络资源 特别的&#xff0c;如果你想直接…

python实践-实现实时语音转文字本地部署版(二)

一、技术栈 python 3.10.6 vosk 需下载对应模型&#xff08;vosk-model-cn-0.22&#xff09;模型下载慢的同学看最后的资源链接。 pyaudio keyboard 二、实现功能 本地化实现麦克风语音录入&#xff0c;实时生成文字&#xff0c;并保存至本地文档。 三、实现代码 fro…

tortoiseSVN 如何克隆项目到本地

导入项目成功&#xff0c;如下图&#xff1a;

解决“QString的split()函数分割中文“报错

在使用Qt平台的QString类里的split()函数&#xff0c;分割.txt文件里中文的字符串时&#xff0c;发现中文会乱码。     问题原因&#xff1a;中文使用UTF-16编码。     解决方法&#xff1a;将.txt文件保存为UTF-16编码&#xff0c;然后使用split()去分割对应的字符串即可。…

云平台结合DeepSeek的AI模型优化实践:技术突破与应用革新

目录 前言 一、技术架构&#xff1a;算力与算法的协同基石 1. 蓝耘平台的核心优势 2. DeepSeek的模型创新 二、应用场景&#xff1a;垂直领域的智能化落地 1. 商业领域&#xff1a;智能推荐与客服 2. 工业领域&#xff1a;质检与流程优化 3. 智慧城市与医…

蓝桥杯(B组)-每日一题(1093字符逆序)

c中函数&#xff1a; reverse(首位置&#xff0c;尾位置&#xff09; reverse(s.begin(),s.end()) 头文件&#xff1a;<algorithm> #include<iostream> #include<algorithm>//运用reverse函数的头文件 using namespace std; int main() {string s;//定义一…

jsherp importItemExcel接口存在SQL注入

一、漏洞简介 很多人说管伊佳ERP&#xff08;原名&#xff1a;华夏ERP&#xff0c;英文名&#xff1a;jshERP&#xff09;是目前人气领先的国产ERP系统虽然目前只有进销存财务生产的功能&#xff0c;但后面将会推出ERP的全部功能&#xff0c;有兴趣请帮点一下 二、漏洞影响 …

一文讲清 AIO BIO NIO的区别

引言 在 Java 编程中&#xff0c;BIO&#xff08;Blocking I/O&#xff09;、NIO&#xff08;Non-blocking I/O&#xff09;和 AIO&#xff08;Asynchronous I/O&#xff09;是三种不同的 I/O 模型&#xff0c;它们在处理输入输出操作时有着不同的机制和特点&#xff0c;但是市…

文心一言大模型的“三级跳”:从收费到免费再到开源,一场AI生态的重构实验

2025年2月&#xff0c;百度文心大模型接连抛出两枚“重磅炸弹”&#xff1a;4月1日起全面免费&#xff0c;6月30日正式开源文心大模型4.5系列。这一系列动作不仅颠覆了李彦宏此前坚持的“闭源优势论”13&#xff0c;更标志着中国AI大模型竞争进入了一个全新的阶段——从技术壁垒…

Uniapp 从入门到精通:基础篇 - 搭建开发环境

Uniapp 从入门到精通:基础篇 - 搭建开发环境 前言一、Uniapp 简介1.1 什么是 Uniapp1.2 Uniapp 的优势二、搭建开发环境前的准备2.1 安装 Node.js2.2 安装 HBuilderX三、创建第一个 Uniapp 项目3.1 打开 HBuilderX 并创建项目3.2 项目结构介绍3.3 运行项目四、配置项目4.1 配置…

CSDN文章质量分查询系统【赠python爬虫、提分攻略】

CSDN文章质量分查询系统 https://www.csdn.net/qc 点击链接-----> CSDN文章质量分查询系统 <------点击链接 点击链接-----> https://www.csdn.net/qc <------点击链接 点击链接-----> CSDN文章质量分查询系统 <------点击链接 点击链…