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

【最佳实践】配置类封装-Async异步注解以及自定义线程池

效果是:能点进去看到自定义的线程池,代表指定自定义的线程池成功!

image-20240411204924405

自定义Async线程池

自定义线程池

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 */
@Configuration
@Slf4j
public class ThreadPoolConfig {
    @Value("${asyncThreadPool.corePoolSize}")
    private int corePoolSize;

    @Value("${asyncThreadPool.maxPoolSize}")
    private int maxPoolSize;

    @Value("${asyncThreadPool.queueCapacity}")
    private int queueCapacity;

    @Value("${asyncThreadPool.keepAliveSeconds}")
    private int keepAliveSeconds;

    @Value("${asyncThreadPool.awaitTerminationSeconds}")
    private int awaitTerminationSeconds;

    @Value("${asyncThreadPool.threadNamePrefix}")
    private String threadNamePrefix;

    /**
     * 线程池配置
     * @return
     */
    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        log.info("---------- 线程池开始加载 ----------");
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(corePoolSize);                        // 核心线程池大小
        threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);                          // 最大线程数
        threadPoolTaskExecutor.setQueueCapacity(keepAliveSeconds);                        // 队列容量
        threadPoolTaskExecutor.setKeepAliveSeconds(queueCapacity);                        // 活跃时间
        //threadPoolTaskExecutor.setAwaitTerminationSeconds(awaitTerminationSeconds);        // 主线程等待子线程执行时间
        threadPoolTaskExecutor.setThreadNamePrefix(threadNamePrefix);        // 线程名字前缀
        // RejectedExecutionHandler:当pool已经达到max-size的时候,如何处理新任务
        //      CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        threadPoolTaskExecutor.initialize(); // 初始化
        log.info("---------- 线程池加载完成 ----------");
        return threadPoolTaskExecutor;
    }
}

application.yml 配置

# @async 线程池配置
asyncThreadPool:
  corePoolSize: 10
  maxPoolSize: 50
  queueCapacity: 1000
  keepAliveSeconds: 60
  awaitTerminationSeconds: 600
  threadNamePrefix: asyncTask-

标准模板:优雅的写法

将配置文件(默认配置)与业务代码分离

MyAsyncThreadPoolExecutorProperties

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "async.thread.pool")
public class ThreadPoolTaskExecutorProperties {
    /**
     * 核心线程数
     */
    private int corePoolSize = 10;

    /**
     * 最大线程数
     */
    private int maxPoolSize = 50;

    /**
     * 队列容量
     */
    private int queueCapacity = 1000;

    /**
     * 线程存活时间
     */
    private int keepAliveSeconds = 60;

    /**
     * 等待终止时间
     */
    private int awaitTerminationSeconds = 600;

    /**
     * 线程名称前缀
     */
    private String threadNamePrefix = "asyncTask-";
}

MyAsyncThreadPoolExecutor

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@EnableAsync
@EnableConfigurationProperties(ThreadPoolTaskExecutorProperties.class)
public class MyAsyncThreadPoolExecutor {

    private final ThreadPoolTaskExecutorProperties properties;

    @Autowired
    public MyAsyncThreadPoolExecutor(ThreadPoolTaskExecutorProperties properties) {
        this.properties = properties;
    }
    @Bean("threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(properties.getCorePoolSize());
        threadPoolTaskExecutor.setMaxPoolSize(properties.getMaxPoolSize());
        threadPoolTaskExecutor.setQueueCapacity(properties.getQueueCapacity());
        threadPoolTaskExecutor.setKeepAliveSeconds(properties.getKeepAliveSeconds());
        threadPoolTaskExecutor.setAwaitTerminationSeconds(properties.getAwaitTerminationSeconds());
        threadPoolTaskExecutor.setThreadNamePrefix(properties.getThreadNamePrefix());
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }
}

测试使用

使用方法:可以指定或者不指定,最好指定!

    /**
     * @Async失效情况: TODO 异步发送方案OOM问题
     */
    @Async("threadPoolTaskExecutor")
    public void testSend(String site) {
        ///notify/v1/send-code?name=http://47.98.233.38:5212/login
        if (StrUtil.isBlank(site)) {
            site = "https://www.xdclass.net/";
        }

        // 发送验证码模拟
        ResponseEntity<String> forEntity = this.restTemplate.getForEntity(site, String.class);
        String body = forEntity.getBody();
        log.info(body);
    }

特征是:会显示用了哪个线程完成任务,但是不会呈现内部的worker执行细节(得看源码)

image-20240411210216507

注解失效问题

【官方】:如下方式会使@Async失效

一、异步方法使用static修饰
二、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
三、异步方法不能与被调用的异步方法在同一个类中
四、类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
五、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解

成功使用的原则是:

  1. 因为底层是由动态代理实现的,所以需要被spring管理
  2. 由spring管理,所以里面的类引用都是**@Autowired或@Resource等注解⾃动注⼊**,全程都要在spring的管辖范围内(方便使用动态代理的方式来完成异步调用),即调用者也必须是spring管理范围内的组件,不允许手动new对象
  3. 方法要求:public、非static非共享、返回值为void、Futrue

特点:

  • 底层还有一个线程池,要么自己实现,要么spring自带(超不推荐)
  • 动态代理实现

其他

简单demo写法

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

@Configuration
@EnableAsync
public class MyAsyncThreadPoolExecutor {
    @Bean("threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(16);
        threadPoolTaskExecutor.setMaxPoolSize(64);
        threadPoolTaskExecutor.setQueueCapacity(1024);
        threadPoolTaskExecutor.setKeepAliveSeconds(60);
        threadPoolTaskExecutor.setAwaitTerminationSeconds(600);
        threadPoolTaskExecutor.setThreadNamePrefix("自定义线程池-");
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }
}

http://www.kler.cn/a/306207.html

相关文章:

  • 【数据价值化】国有企业数据资产入表及估值实践指南:挖掘数字资产新价值
  • MySQL(5)【数据类型 —— 字符串类型】
  • python——面向对象
  • python 2小时学会八股文-数据结构
  • 【数据结构与算法】第12课—数据结构之归并排序
  • Ruby编程语言全景解析:从基础到进阶
  • 对操作系统(OS)管理和进程的理解
  • 28 线性表 · 栈
  • golang的GC(三色标记法+混合写屏障)学习笔记
  • 第一篇---滑动窗口最大值、前 K 个高频元素
  • 初识爬虫2
  • Linux删除SSH生成的密钥对
  • 探索Python的Excel世界:openpyxl的魔法之旅
  • 【homebrew安装】踩坑爬坑教程
  • 路由策略原理与配置
  • C#笔记11 获取线程及其信息,什么是优先级、单元状态、线程状态、执行状态、线程名称以及其他属性?
  • 一文速通calcite结合flink理解SQL从文本变成执行计划详细过程
  • Kubernetes Pod镜像的3种状态
  • STM32-UART配置注释
  • 标准库标头 <bit>(C++20)学习
  • 计算机网络 --- 计算机网络性能【七大性能指标】
  • 如何精确统计Pytorch模型推理时间
  • c语言写的环形队列
  • emWin5的图片半透明之旅
  • 高级java每日一道面试题-2024年9月12日-架构篇[DDD领域驱动篇]-如何使用领域驱动设计(DDD)中的事务脚本模式?
  • Spring4-IoC2-基于注解管理bean