SpringBoot实现线程池

现在由于系统越来越复杂,导致很多接口速度变慢,这时候就会想到可以利用线程池来处理一些耗时并不影响系统的操作。

新建Spring Boot项目

1. ExecutorConfig.xml

新建线程池配置文件。

@Configuration
@EnableAsync
public class ExecutorConfig {

    private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);

    @Value("${async.executor.thread.core_pool_size}")
    private int corePoolSize;
    @Value("${async.executor.thread.max_pool_size}")
    private int maxPoolSize;
    @Value("${async.executor.thread.queue_capacity}")
    private int queueCapacity;
    @Value("${async.executor.thread.name.prefix}")
    private String namePrefix;

    @Bean(name = "asyncServiceExecutor")
    public Executor asyncServiceExecutor() {
        logger.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        executor.setQueueCapacity(queueCapacity);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix(namePrefix);

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
}

2. application.yml

@Value配置在application.yml,可以参考配置

# 异步线程配置
async:
  executor:
    thread:
      # 配置核心线程数
      core_pool_size: 10
      # 配置最大线程数
      max_pool_size: 20
      # 配置队列大小
      queue_capacity: 99999
      # 配置线程池中的线程的名称前缀
      name:
        prefix: async-service-

3. AsyncService.java

创建一个 Service 接口,是异步线程的接口,将方法写入其实现类即可

public interface AsyncService {

    /**
      * 执行异步任务的方法,参数自己可以添加
      */
    void executeAsync();
}

4. AsyncServiceImpl.java

实现类,用来写业务逻辑

@Service
public class AsyncServiceImpl implements AsyncService {

    private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class);

    @Override
    @Async("asyncServiceExecutor")
    public void executeAsync() {
        logger.info("start executeAsync");

        System.out.println("异步线程执行开始了");
        System.out.println("可以将耗时的操作放到这里执行了");

        logger.info("end executeAsync");
    }
}

++将 Service 层的服务异步化,在executeAsync()方法上增加注解@Async("asyncServiceExecutor"),asyncServiceExecutor方法是前面ExecutorConfig.java中的方法名,表明executeAsync方法进入的线程池是asyncServiceExecutor方法创建的。++

5. AsyncController.java

在控制器里面注入AsyncService,调用其中的方法即可

@Autowired
private AsyncService asyncService;

@GetMapping("/async")
public void async(){
    asyncService.executeAsync();
}

6. 用Postman进行测试

打印log入下

2021-06-16 22:15:47.655  INFO 10516 --- [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程执行开始了
可以将耗时的操作放到这里执行了
2021-06-16 22:15:47.655  INFO 10516 --- [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-06-16 22:15:47.770  INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程执行开始了
可以将耗时的操作放到这里执行了
2021-06-16 22:15:47.770  INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-06-16 22:15:47.816  INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程执行开始了
可以将耗时的操作放到这里执行了
2021-06-16 22:15:47.816  INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-06-16 22:15:48.833  INFO 10516 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程执行开始了
可以将耗时的操作放到这里执行了
2021-06-16 22:15:48.834  INFO 10516 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-06-16 22:15:48.986  INFO 10516 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程执行开始了
可以将耗时的操作放到这里执行了
2021-06-16 22:15:48.987  INFO 10516 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
至此简单的线程池已经实现了。

5. 将当前线程池的运行状况打印出来

5.1 VisiableThreadPoolTaskExecutor.java

public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {

    private static final Logger logger = LoggerFactory.getLogger(VisiableThreadPoolTaskExecutor.class);

    private void showThreadPoolInfo(String prefix) {
        ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();

        if (null == threadPoolExecutor) {
            return;
        }

        logger.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
                this.getThreadNamePrefix(),
                prefix,
                threadPoolExecutor.getTaskCount(),
                threadPoolExecutor.getCompletedTaskCount(),
                threadPoolExecutor.getActiveCount(),
                threadPoolExecutor.getQueue().size());
    }

    @Override
    public void execute(Runnable task) {
        showThreadPoolInfo("1. do execute");
        super.execute(task);
    }

    @Override
    public void execute(Runnable task, long startTimeout) {
        showThreadPoolInfo("2. do execute");
        super.execute(task, startTimeout);
    }

    @Override
    public Future<?> submit(Runnable task) {
        showThreadPoolInfo("1. do submit");
        return super.submit(task);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        showThreadPoolInfo("2. do submit");
        return super.submit(task);
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        showThreadPoolInfo("1. do submitListenable");
        return super.submitListenable(task);
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        showThreadPoolInfo("2. do submitListenable");
        return super.submitListenable(task);
    }
}

5.2 修改asyncServiceExecutor.java

修改ExecutorConfig.java的asyncServiceExecutor方法,将ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor()改为ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor()

@Bean(name = "asyncServiceExecutor")
    public Executor asyncServiceExecutor() {
        logger.info("start asyncServiceExecutor");
        //在这里修改
        ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        executor.setQueueCapacity(queueCapacity);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix(namePrefix);

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }

5.3 使用Postman进行测试

2021-06-16 22:23:30.951  INFO 14088 --- [nio-8087-exec-2] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [0], completedTaskCount [0], activeCount [0], queueSize [0]
2021-06-16 22:23:30.952  INFO 14088 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程执行开始了
可以将耗时的操作放到这里执行了
2021-06-16 22:23:30.953  INFO 14088 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-06-16 22:23:31.351  INFO 14088 --- [nio-8087-exec-3] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [1], completedTaskCount [1], activeCount [0], queueSize [0]
2021-06-16 22:23:31.353  INFO 14088 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程执行开始了
可以将耗时的操作放到这里执行了
2021-06-16 22:23:31.353  INFO 14088 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-06-16 22:23:31.927  INFO 14088 --- [nio-8087-exec-5] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [2], completedTaskCount [2], activeCount [0], queueSize [0]
2021-06-16 22:23:31.929  INFO 14088 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程执行开始了
可以将耗时的操作放到这里执行了
2021-06-16 22:23:31.930  INFO 14088 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-06-16 22:23:32.496  INFO 14088 --- [nio-8087-exec-7] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [3], completedTaskCount [3], activeCount [0], queueSize [0]
2021-06-16 22:23:32.498  INFO 14088 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程执行开始了
可以将耗时的操作放到这里执行了
2021-06-16 22:23:32.499  INFO 14088 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync

可以看到上面async-service-, 2. do submit,taskCount [3], completedTaskCount [3], activeCount [0], queueSize [0]关于线程的信息都打印出来了。

到此这篇关于SpringBoot实现线程池的文章就介绍到这了,更多相关SpringBoot 线程池内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Springboot 如何使用@Async整合线程池

    Springboot @Async整合线程池 开篇咱们先来聊聊线程池这个概念,或者说为什么要使用线程池:简言之,充分利用cpu资源,提高程序执行时间,但是相反,线程池异常提示.主线程和子线程事务问题也是显而易见的. 那么@Async这个注解又是什么做用呢?其实就是标识方法为异步任务的一个注解,默认会自己维护一个线程池(存在弊端),利用子线程去执行任务:那么如果把这两者结合的话,线程池+Async又会有什么效果呢! 循序渐进 提到线程池,可以采用Executors提供四种线程池下,使用某些特性的场

  • SpringBoot+slf4j线程池全链路调用日志跟踪问题及解决思路(二)

    本项目源码已在多个项目中实践 接着上一篇文章,项目中使用了线程池,那么子线程中日志就会丢失traceId,下面讲解如何实现子线程中的traceId日志跟踪. 解决思路 子线程在打印日志的过程中traceId将丢失,解决方式为重写线程池,将主线程的traceId继续传递到子线程中.当然,对于直接new创建线程的情况不考略[实际应用中应该避免这种用法]. 继承ThreadPoolExecutor,重写执行任务的方法 public final class OverrideThreadPoolExecu

  • SpringBoot2线程池定义使用方法解析

    我们都知道spring只是为我们简单的处理线程池,每次用到线程总会new 一个新的线程,效率不高,所以我们需要自定义一个线程池. 定义线程池 @Slf4j @EnableAsync @Configuration public class AsyncExecutorConfig implements AsyncConfigurer { @Bean public ThreadPoolTaskExecutor asyncServiceExecutor() { //返回可用处理器的虚拟机的最大数量不小于

  • springboot2.0以上调度器配置线程池的实现

    一 我们使用@EnableScheduling 开启spring task 调度器的时候,发现此调度器默认配置为单线程的. 二 打开注解发现其配置信息在此SchedulingConfiguration类中.发现其创建了ScheduledTaskRegistrar类 研读代码不难发现调度器默认配置是如下代码,线程池为单线程的. protected void scheduleTasks() { if (this.taskScheduler == null) { this.localExecutor

  • Springboot应用中线程池配置详细教程(最新2021版)

    前言:日常开发中我们常用ThreadPoolExecutor提供的线程池服务帮我们管理线程,在Springboot中更是提供了@Async注解来简化业务逻辑提交到线程池中执行的过程.由于Springboot中默认设置的corePoolSize=1和queyeCapacity=Integer.MAX_VALUE,相当于采用单线程处理所有任务,这就与多线程的目的背道而驰,所以这就要求我们在使用@Async注解时要配置线程池.本文就讲述下Springboot应用下的线程池配置. 背景知识:Spring

  • springboot中@Async默认线程池导致OOM问题

    前言: 1.最近项目上在测试人员压测过程中发现了OOM问题,项目使用springboot搭建项目工程,通过查看日志中包含信息:unable to create new native thread 内存溢出的三种类型: 1.第一种OutOfMemoryError: PermGen space,发生这种问题的原意是程序中使用了大量的jar或class 2.第二种OutOfMemoryError: Java heap space,发生这种问题的原因是java虚拟机创建的对象太多 3.第三种OutOfM

  • SpringBoot 多任务并行+线程池处理的实现

    前言 前几篇文章着重介绍了后端服务数据库和多线程并行处理优化,并示例了改造前后的伪代码逻辑.当然了,优化是无止境的,前人栽树后人乘凉.作为我们开发者来说,既然站在了巨人的肩膀上,就要写出更加优化的程序. SpringBoot开发案例之JdbcTemplate批量操作 SpringBoot开发案例之CountDownLatch多任务并行处理 改造 理论上讲,线程越多程序可能更快,但是在实际使用中我们需要考虑到线程本身的创建以及销毁的资源消耗,以及保护操作系统本身的目的.我们通常需要将线程限制在一定

  • 深入学习springboot线程池的使用和扩展

    前言 我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行,今天我们就来实战体验这个线程池服务: 实战环境 windowns10: jdk1.8: springboot 1.5.9.RELEASE: 开发工具:IntelliJ IDEA: 实战源码 本次实战的源码可以在我的GitHub下载,地址:git@github.com:zq2599/blog_demos.git,项目主页: 这里面有多

  • SpringBoot实现线程池

    现在由于系统越来越复杂,导致很多接口速度变慢,这时候就会想到可以利用线程池来处理一些耗时并不影响系统的操作. 新建Spring Boot项目 1. ExecutorConfig.xml 新建线程池配置文件. @Configuration @EnableAsync public class ExecutorConfig { private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class); @Val

  • springboot使用线程池(ThreadPoolTaskExecutor)示例

    目录 线程池创建 线程池参数 线程池测试1(核心线程数量) 线程池测试2(当核心线程数量和最大线程数量不够时) 总结 代码仓库:gitee 线程池创建 @Configuration @EnableAsync public class TaskPoolConfig { @Bean("syncExecutorPool") public Executor taskExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPool

  • springboot创建线程池的两种方式小结

    目录 springboot创建线程池两种方式 1.使用static代码块创建 2.使用@Configuration @bean注解,程序启动时创建 springboot开启线程池 定义线程池 使用 springboot创建线程池两种方式 1.使用static代码块创建 这样的方式创建的好处是当代码用到线程池的时候才会初始化核心线程数 具体代码如下: public class HttpApiThreadPool { /** 获取当前系统的CPU 数目*/ static int cpuNums =

  • springboot使用线程池(ThreadPoolTaskExecutor)示例

    目录 线程池创建 线程池参数 线程池测试1(核心线程数量) 线程池测试2(当核心线程数量和最大线程数量不够时) 总结 代码仓库:gitee 线程池创建 @Configuration @EnableAsync public class TaskPoolConfig { @Bean("syncExecutorPool") public Executor taskExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPool

  • Springboot 配置线程池创建线程及配置 @Async 异步操作线程池详解

    目录 前言 一.创建一个Springboot Web项目 二.新建ThreadPoolConfig 三.新建controller测试 四.演示结果 前言 众所周知,创建显示线程和直接使用未配置的线程池创建线程,都会被阿里的大佬给diss,所以我们要规范的创建线程. 至于 @Async 异步任务的用处是不想等待方法执行完就返回结果,提高软件前台响应速度,一个程序中会用到很多异步方法,所以需要使用线程池管理,防止影响性能. 一.创建一个Springboot Web项目 需要一个Springboot项

  • 基于springcloud异步线程池、高并发请求feign的解决方案

    ScenTaskTestApplication.java package com.test; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @author scen *

随机推荐