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

文章目录

      • 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 中的多线程编程技术!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【科研绘图系列】R语言绘制小提琴图、散点图和韦恩图(violin scatter plot Venn)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载画图1画图2画图3画图4画图5画图6画图7参考介绍 【科研绘图系列】R语言绘制小提琴图、散点图和韦恩图(violin & scatter plot & Venn) 加载R包 library…

IMX6ULL的ALT0、ALT1、ALT2、ALT3、ALT4等是啥意思?

在IMX6ULL的手册IMX6ULLRM.pdf中&#xff0c;发现了题目中这些描述&#xff0c;相关截图如下&#xff1a; 那么红框中的ALT0、ALT1、ALT2、ALT3、ALT4等是啥意思呢&#xff1f; 在IMX6ULL及其他NXP&#xff08;Freescale&#xff09;芯片中&#xff0c;ALT0、ALT1、ALT2、ALT…

Android Http-server 本地 web 服务

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

DeepSeek 冲击(含本地化部署实践)

DeepSeek无疑是春节档最火爆的话题&#xff0c;上线不足一月&#xff0c;其全球累计下载量已达4000万&#xff0c;反超ChatGPT成为全球增长最快的AI应用&#xff0c;并且完全开源。那么究竟DeepSeek有什么魔力&#xff0c;能够让大家趋之若鹜&#xff0c;他又将怎样改变世界AI格…

神经网络八股(1)

1.什么是有监督学习&#xff0c;无监督学习 有监督学习是带有标签的&#xff0c;无监督学习是没有标签的&#xff0c;简单来说就是有监督学习的输入输出都是固定的&#xff0c;已知的&#xff0c;无监督学习输入是已知的&#xff0c;输出是不固定的&#xff0c;无监督学习是通…

DeepSeek 助力 Vue 开发:打造丝滑的瀑布流布局(Masonry Layout)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

【分布式理论14】分布式数据库存储:分表分库、主从复制与数据扩容策略

文章目录 一、分表分库1. 数据分表的必要性与方式2. 数据分库原则与优势 二、主从复制1. 读写分离架构设计2. 数据复制方式3. MySQL实现主从复制4. MySQL主从复制实践与高可用方案 三、数据扩容 随着业务的不断发展和数据量的增长&#xff0c;传统的单机关系型数据库已经逐渐不…

从传统到轻量级5G:网络架构演变与优化路径

轻量级5G​​​​ 随着5G技术的不断发展&#xff0c;通信网络架构正经历着前所未有的变革。传统的5G核心网架构虽然在性能和容量方面表现出色&#xff0c;但在灵活性、部署效率以及成本控制方面却面临一些挑战。为了应对日益复杂的通信需求&#xff0c;轻量级5G核心网成为了一种…

搭建Kubernetes (K8s) 集群----Centos系统

前期准备 准备3台Linux虚拟机&#xff08;CentOS系统&#xff09;&#xff0c;参考 https://carry.blog.csdn.net/article/details/144578009https://carry.blog.csdn.net/article/details/144578009搭建Docker环境&#xff0c;参考 https://carry.blog.csdn.net/article/de…

OpenSSL实验

文章目录 一、OpenSSL安装二、OpenSSL配置常见路径查找配置文件的方法示例**1. 配置文件结构****2. 主要段落及其作用****(1) 默认段&#xff08;Default Section&#xff09;****(2) OID段&#xff08;OID Section&#xff09;****(3) CA相关段&#xff08;CA Section&#xf…

51单片机-按键

1、独立按键 1.1、按键介绍 轻触开关是一种电子开关&#xff0c;使用时&#xff0c;轻轻按开关按钮就可使开关接通&#xff0c;当松开手时&#xff0c;开关断开。 1.2、独立按键原理 按键在闭合和断开时&#xff0c;触点会存在抖动现象。P2\P3\P1都是准双向IO口&#xff0c;…

DeepSeek动画视频全攻略:从架构到本地部署

DeepSeek 本身并不直接生成动画视频,而是通过与一系列先进的 AI 工具和传统软件协作,完成动画视频的制作任务。这一独特的架构模式,使得 DeepSeek 在动画视频创作领域发挥着不可或缺的辅助作用。其核心流程主要包括脚本生成、画面设计、视频合成与后期处理这几个关键环节。 …

EasyRTC智能硬件:实时畅联、沉浸互动、消音护航

在当今智能硬件迅猛发展的时代&#xff0c;音视频通讯技术已成为设备与用户、设备与设备间不可或缺的沟通纽带。而EasyRTC&#xff0c;凭借其无可比拟的实时性能、卓越的互动感受以及强大的交互实力&#xff0c;正逐步演变为智能硬件领域的“超级动力”核心。特别是其倾力打造的…

[AI相关]Unity的C#代码如何简写

是一个某培训机构的飞行棋教学源码 不知道&#xff0c;是否有人想知道怎么可以简写 &#xff08;这个问AI&#xff0c;DeepSeek也应该找不到答案的&#xff09; 静态变量 属性引用 单例 注入 一些UnityEvent特性就不说了。。。 IL 注入 运算符号改写

ubuntu 执行 sudo apt-get update 报错

记录一下&#xff0c;遇到这个问题了&#xff0c;网络上看到的解决办法&#xff0c;亲测有效 执行sudo apt-get update ,却报以下错误&#xff0c;“SECURITY: URL redirect target contains control characters rejecting ” 经检查发现&#xff0c;/etc/apt/source.list 下的…

蓝桥杯学习大纲

&#xff08;致酷德与热爱算法、编程的小伙伴们&#xff09; 在查阅了相当多的资料后&#xff0c;发现没有那篇博客、文章很符合我们备战蓝桥杯的学习路径。所以&#xff0c;干脆自己整理一篇&#xff0c;欢迎大家补充&#xff01; 一、蓝桥必备高频考点 我们以此为重点学习…

【插件】前端生成word 文件

文章目录 1、背景2、方式一&#xff1a;html-docx-js2.1 具体代码2.2 前端生成word文件的样式2.3 总结 3、方式二&#xff1a;pizzip docxtemplater3.1 具体代码3.2 前端生成word文件的样式3.3 总结 4、参考链接 1、背景 在实际开发中&#xff0c;业务需要&#xff0c;需要把数…

4. grafana(7.5.17)功能菜单简介

点击可以返回home页面 搜索Dashboard 新建按钮&#xff1a;用户创建Dashboard、文件夹。以及导入外部&#xff08;社区&#xff09;Dashboard 用于查看活管理Dashboard&#xff0c;包括home、Manage、playlists、snapshots功能 explore&#xff08;探索&#xff09;&#x…

QT之改变鼠标样式

QT改变鼠标图片 资源路径如下 代码实现 QPixmap customCursorPixmap(":/images/mouse.png");QCursor customCursor(customCursorPixmap);QWidget::setCursor(customCursor); // 可以设置为整个窗口或特定控件QWidget::setCursor(); // 设置为透明光标&#xff0c…

ctfshow web入门 web11-web24

web11 web12 进来浏览网站&#xff0c;底部有一串数字&#xff0c;根据提示可能有用&#xff0c;访问robots.txt&#xff0c;发现禁止访问/admin/&#xff0c;进去看看发现需要输入用户名和密码&#xff0c;刚想爆破就猜对了&#xff0c;用户名是admin&#xff0c;密码是页面下…