Tianyi's Blog Tianyi's Blog
首页
  • 计算机网络
  • 操作系统
  • 计算机科学
  • Nginx
  • Vue框架
  • 环境配置
  • Java
  • JVM
  • Spring框架
  • Redis
  • MySQL
  • RabbitMQ
  • Kafka
  • Mirror Sites
  • Dev Tools
  • Docker
  • Jenkins
  • Scripts
  • Windows
  • 科学上网
  • 旅行
  • 网站日记
  • 软件
  • 电子产品
  • 杂野
  • 分类
  • 友情链接
GitHub (opens new window)

Tianyi

一直向前,永不停止
首页
  • 计算机网络
  • 操作系统
  • 计算机科学
  • Nginx
  • Vue框架
  • 环境配置
  • Java
  • JVM
  • Spring框架
  • Redis
  • MySQL
  • RabbitMQ
  • Kafka
  • Mirror Sites
  • Dev Tools
  • Docker
  • Jenkins
  • Scripts
  • Windows
  • 科学上网
  • 旅行
  • 网站日记
  • 软件
  • 电子产品
  • 杂野
  • 分类
  • 友情链接
GitHub (opens new window)
  • Java

  • Golang

  • JVM的奇妙世界

  • Spring

  • Spring增强封装

    • 配置类封装-Redis
    • 配置类封装-Async异步注解以及自定义线程池
      • 自定义Async线程池
        • 自定义线程池
        • application.yml 配置
      • 标准模板:优雅的写法
        • MyAsyncThreadPoolExecutorProperties
        • MyAsyncThreadPoolExecutor
      • 测试使用
      • 注解失效问题
      • 其他
        • 简单demo写法
    • 配置类封装-国际化MessageSource
    • 配置类封装-响应体、全局异常处理
    • 配置类封装-动态切换数据源
    • 配置类封装-RestTemplate
    • 配置类封装-网关限流
  • Redis

  • MySQL

  • RabbitMQ

  • Kafka

  • 分享

  • 后端
  • Spring增强封装
tianyi
2022-09-18
目录
自定义Async线程池
自定义线程池
application.yml 配置
标准模板:优雅的写法
MyAsyncThreadPoolExecutorProperties
MyAsyncThreadPoolExecutor
测试使用
注解失效问题
其他
简单demo写法

配置类封装-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;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

# application.yml 配置

# @async 线程池配置
asyncThreadPool:
  corePoolSize: 10
  maxPoolSize: 50
  queueCapacity: 1000
  keepAliveSeconds: 60
  awaitTerminationSeconds: 600
  threadNamePrefix: asyncTask-
1
2
3
4
5
6
7
8

# 标准模板:优雅的写法

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

# 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-";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 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;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 测试使用

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

    /**
     * @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);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

特征是:会显示用了哪个线程完成任务,但是不会呈现内部的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;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
完善页面 (opens new window)
配置类封装-Redis
配置类封装-国际化MessageSource

← 配置类封装-Redis 配置类封装-国际化MessageSource→

最近更新
01
JDK
02-23
02
BadTasteCode && 优化
09-11
03
Gradle 实践操作指南及最佳实践
09-11
更多文章>
Theme by Vdoing | Copyright © 2021-2025 Tandy | 粤ICP备2023113440号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式