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

Spring线程池学习笔记

Spring提供了多种方式来配置和使用线程池,最常见的是通过TaskExecutorThreadPoolTaskExecutor

Spring线程池

TaskExecutor 接口

TaskExecutor 是Spring框架中的一个接口,它是对Java的Executor接口的简单封装。它的主要目的是为了提供一个统一的接口来执行任务。

public interface TaskExecutor extends Executor {
    void execute(Runnable task);
}

ThreadPoolTaskExecutor

ThreadPoolTaskExecutor 是Spring提供的一个实现类,它是对Java的ThreadPoolExecutor的封装,提供了更多的配置选项和Spring集成。

配置 ThreadPoolTaskExecutor

通过XML配置或Java配置来定义ThreadPoolTaskExecutor

Java配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
public class ThreadPoolConfig {

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5); // 核心线程数
        executor.setMaxPoolSize(10); // 最大线程数
        executor.setQueueCapacity(25); // 队列容量
        executor.setThreadNamePrefix("MyThread-"); // 线程名前缀
        executor.initialize();
        return executor;
    }
}

XML配置

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="5" />
    <property name="maxPoolSize" value="10" />
    <property name="queueCapacity" value="25" />
    <property name="threadNamePrefix" value="MyThread-" />
</bean>
使用 ThreadPoolTaskExecutor

配置好线程池后,通过注入TaskExecutor来使用它。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    public void executeTask(Runnable task) {
        taskExecutor.execute(task);
    }
}

线程池的参数解释

  • corePoolSize: 核心线程数,即使线程空闲也不会被回收。
  • maxPoolSize: 最大线程数,当队列满了之后,线程池会创建新的线程,直到达到最大线程数。
  • queueCapacity: 任务队列的容量,当线程数达到核心线程数时,新任务会被放入队列中等待执行。
  • threadNamePrefix: 线程名前缀,方便调试和日志记录。

线程池的工作流程

  1. 当有任务提交时,线程池会首先尝试使用核心线程来执行任务。
  2. 如果核心线程都在忙,任务会被放入队列中等待。
  3. 如果队列满了,线程池会创建新的线程,直到达到最大线程数。
  4. 如果线程数达到最大线程数且队列也满了,新的任务会被拒绝(通过设置拒绝策略来处理)

拒绝策略

当线程池和队列都满了,新的任务会被拒绝。Spring提供了几种拒绝策略:

  • AbortPolicy: 直接抛出异常(默认策略)。
  • CallerRunsPolicy: 由调用线程来执行任务。
  • DiscardPolicy: 直接丢弃任务。
  • DiscardOldestPolicy: 丢弃队列中最旧的任务,然后尝试重新提交新任务。

通过setRejectedExecutionHandler方法来设置拒绝策略。

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 满了调用线程执行,认为重要任务

关闭线程池

在应用关闭时,确保正确关闭线程池,以释放资源。

taskExecutor.shutdown();

异步执行

Spring还提供了@Async注解来支持异步任务执行。
将方法标记为异步,Spring会自动使用配置的线程池来执行这些方法。

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    @Async
    public void asyncMethod() {
        // 异步执行的代码
    }
}

统一项目管理的线程池封装异常

优雅停机

线程池的waitForTasksToCompleteOnShutdown 的 默认参数

private boolean waitForTasksToCompleteOnShutdown = false;

Spring 的线程池为什么可以优雅停机,就是继承了DisposableBean的Destroy会被Spring回调

在这里插入图片描述

如何捕获线程异常

如果不处理的话
在这里插入图片描述

线程可以手动设置处理类

在这里插入图片描述

自定义未捕获异常时捕获并处理异常信息

@Slf4j
public class MyUncaughtExceptionHandler implements  Thread.UncaughtExceptionHandler{
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        log.error("Exception in thread", e);
    }

}

单个线程池测试

		Thread thread =  new Thread(
                ()->{
                    log.error("123");
                    throw new RuntimeException("异常");
                }
        );
        thread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        thread.start();

在这里插入图片描述

项目共用线程池

自定义未捕获异常时捕获并处理异常信息

@Slf4j
public class MyUncaughtExceptionHandler implements  Thread.UncaughtExceptionHandler{
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        log.error("Exception in thread", e);
    }

}

自定义线程工厂(设计模式——装饰器)

@AllArgsConstructor
public class MyThreadFactory implements ThreadFactory {
    private static final MyUncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER = new MyUncaughtExceptionHandler();
    private ThreadFactory originalThreadFactory;
    /**
     * @param r a runnable to be executed by new thread instance
     * @description 额外装饰我们需要的线程
     * @return
     */
    @Override
    public Thread newThread(Runnable r) {
       Thread thread = originalThreadFactory.newThread(r);
       thread.setUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER);
       return thread;
    }
}

创建ThreadPoolConfig

@Configuration
@EnableAsync
public class ThreadPoolConfig implements AsyncConfigurer {
    /**
     * 项目共用线程池,用于处理核心异步任务。
     */
    public static final String MYTHREAD_EXECUTOR= "MyThreadExecutor";
	/**
     * 配置项目共用线程池,用于处理核心业务逻辑。
     *
     * 线程池配置:
     * - 核心线程数:10
     * - 最大线程数:10(固定大小线程池)
     * - 队列容量:200(缓冲待处理任务)
     * - 线程名称前缀:MyThread-executor-
     * - 拒绝策略:调用线程执行(保障重要任务不丢失)
     *
     * @return 配置完成的线程池实例。
     */
    @Bean(MYTHREAD_EXECUTOR)
    @Primary
    public ThreadPoolTaskExecutor mallchatExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("MyThread-executor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setThreadFactory(new MyThreadFactory(executor));
        executor.initialize();
        return executor;
    }
}

测试

@Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Test
    public void thread2(){
        threadPoolTaskExecutor.execute(()->{
            log.error("123");
            throw new RuntimeException("异常");
        });
    }

在这里插入图片描述

总结

Spring中的线程池配置和使用非常灵活,能够满足大多数并发任务的需求。通过合理配置线程池参数,有效地管理资源,提高应用的并发处理能力。

相关文章:

  • 【原创】Ollama Test API For Linux/MacOS/Unix
  • 飞机大战lua迷你世界脚本
  • 并发编程(线程基础)面试题及原理
  • 老榕树的Java专题:SQL 视图:提升数据处理效率的实用工具
  • IO基础知识和练习
  • 学习路程十二 langchain核心Agent
  • C#释放内存空间的方法
  • Free Auto Clicker - 在任意位置自动重复鼠标点击
  • xss笔记与打靶(更新中)
  • Masscan下载Linux安装
  • Powershell批量压缩并上载CSV数据文件到Box企业云盘
  • 基于Matlab的多目标粒子群优化
  • csrf与ssrf学习笔记
  • 使用WebSocket进行通信的图形用户界面应用程序
  • 004build在设计页面上的使用
  • 长时间目标跟踪算法(3)-GlobalTrack:A Simple and Strong Baseline for Long-termTracking
  • 【蓝桥杯单片机】第十二届省赛
  • 计算机毕业设计SpringBoot+Vue.js航空机票预定系统(源码+文档+PPT+讲解)
  • 信息技术知识赛系统设计与实现(代码+数据库+LW)
  • Metasploit multi/handler 模块高级选项解析
  • 多图|多款先进预警机亮相雷达展,专家:中国预警机已达世界先进水平
  • 从良渚到三星堆:一江水串起了5000年的文明对话
  • 有关“普泽会”,俄官方表示:有可能
  • 海昏侯博物馆展览上新,“西汉帝陵文化展”将持续展出3个月
  • 师爷、文士、畸人:会稽范啸风及其著述
  • 获派驻6年后,中国驻厄瓜多尔大使陈国友即将离任