0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何正确使用SpringBoot中的线程池

Android编程精选 来源:CSDN博客 作者:如漩涡 2021-09-02 17:14 次阅读

来自丨CSDN

https://blog.csdn.net/m0_37701381/article/details/81072774

使用步骤

先创建一个线程池的配置,让Spring Boot加载,用来定义如何创建一个ThreadPoolTaskExecutor,要使用@Configuration和@EnableAsync这两个注解,表示这是个配置类,并且是线程池的配置类

@Configuration@EnableAsyncpublic 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;

}

}

@Value是我配置在application.properties,可以参考配置,自由定义

# 异步线程配置# 配置核心线程数

async.executor.thread.core_pool_size = 5

# 配置最大线程数

async.executor.thread.max_pool_size = 5

# 配置队列大小

async.executor.thread.queue_capacity = 99999

# 配置线程池中的线程的名称前缀

async.executor.thread.name.prefix = async-service-

创建一个Service接口,是异步线程的接口

public interface AsyncService {

/**

* 执行异步任务

* 可以根据需求,自己加参数拟定,我这里就做个测试演示

*/

void executeAsync();

}

实现类

@Servicepublic 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方法创建的。

接下来就是在Controller里或者是哪里通过注解@Autowired注入这个Service

@Autowiredprivate AsyncService asyncService;

@GetMapping(“/async”)

public void async(){

asyncService.executeAsync();

}

用postmain或者其他工具来多次测试请求一下

2018-07-16 2247.655 INFO 10516 --- [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync

异步线程要做的事情

可以在这里执行批量插入等耗时的事情

2018-07-16 2247.655 INFO 10516 --- [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync

2018-07-16 2247.770 INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync

异步线程要做的事情

可以在这里执行批量插入等耗时的事情

2018-07-16 2247.770 INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync

2018-07-16 2247.816 INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync

异步线程要做的事情

可以在这里执行批量插入等耗时的事情

2018-07-16 2247.816 INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync

2018-07-16 2248.833 INFO 10516 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync

异步线程要做的事情

可以在这里执行批量插入等耗时的事情

2018-07-16 2248.834 INFO 10516 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync

2018-07-16 2248.986 INFO 10516 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync

异步线程要做的事情

可以在这里执行批量插入等耗时的事情

2018-07-16 2248.987 INFO 10516 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync

通过以上日志可以发现,[async-service-]是有多个线程的,显然已经在我们配置的线程池中执行了,并且每次请求中,controller的起始和结束日志都是连续打印的,表明每次请求都快速响应了,而耗时的操作都留给线程池中的线程去异步执行;

虽然我们已经用上了线程池,但是还不清楚线程池当时的情况,有多少线程在执行,多少在队列中等待呢?这里我创建了一个ThreadPoolTaskExecutor的子类,在每次提交线程的时候都会将当前线程池的运行状况打印出来

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import org.springframework.util.concurrent.ListenableFuture;

import java.util.concurrent.Callable;

import java.util.concurrent.Future;

import java.util.concurrent.ThreadPoolExecutor;

/**

* @Author: ChenBin

*/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);

}

}

如上所示,showThreadPoolInfo方法中将任务总数、已完成数、活跃线程数,队列大小都打印出来了,然后Override了父类的execute、submit等方法,在里面调用showThreadPoolInfo方法,这样每次有任务被提交到线程池的时候,都会将当前线程池的基本情况打印到日志中;

修改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;

}

再次启动该工程测试

2018-07-16 2230.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]

2018-07-16 2230.952 INFO 14088 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync

异步线程要做的事情

可以在这里执行批量插入等耗时的事情

2018-07-16 2230.953 INFO 14088 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync

2018-07-16 2231.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]

2018-07-16 2231.353 INFO 14088 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync

异步线程要做的事情

可以在这里执行批量插入等耗时的事情

2018-07-16 2231.353 INFO 14088 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync

2018-07-16 2231.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]

2018-07-16 2231.929 INFO 14088 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync

异步线程要做的事情

可以在这里执行批量插入等耗时的事情

2018-07-16 2231.930 INFO 14088 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync

2018-07-16 2232.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]

2018-07-16 2232.498 INFO 14088 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync

异步线程要做的事情

可以在这里执行批量插入等耗时的事情

2018-07-16 2232.499 INFO 14088 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync

注意这一行日志:

2018-07-16 2232.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]

这说明提交任务到线程池的时候,调用的是submit(Callable task)这个方法,当前已经提交了3个任务,完成了3个,当前有0个线程在处理任务,还剩0个任务在队列中等待,线程池的基本情况一路了然;

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • spring
    +关注

    关注

    0

    文章

    340

    浏览量

    14343
  • 线程池
    +关注

    关注

    0

    文章

    57

    浏览量

    6846
  • SpringBoot
    +关注

    关注

    0

    文章

    173

    浏览量

    178

原文标题:SpringBoot中的线程池,你真的会用么?

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    socket 多线程编程实现方法

    在现代网络编程,多线程技术被广泛应用于提高服务器的并发处理能力。Socket编程是网络通信的基础,而将多线程技术应用于Socket编程,可以显著提升服务器的性能。 多线程编程的基本概
    的头像 发表于 11-12 14:16 358次阅读

    怎么在JAVA确定线性大小

    在JAVA确定线性大小,分别介绍CPU密集型任务和I/O密集型任务及其处理方法。
    的头像 发表于 10-24 14:02 189次阅读

    Python线程和多进程的区别

    Python作为一种高级编程语言,提供了多种并发编程的方式,其中多线程与多进程是最常见的两种方式之一。在本文中,我们将探讨Python线程与多进程的概念、区别以及如何使用线程
    的头像 发表于 10-23 11:48 400次阅读
    Python<b class='flag-5'>中</b>多<b class='flag-5'>线程</b>和多进程的区别

    买药秒送 JADE动态线程实践及原理浅析

    一、背景及JADE介绍 买药秒送是健康即时零售业务新的核心流量场域,面对京东首页高流量曝光,我们对频道页整个技术架构方案进行升级,保障接口高性能、系统高可用。 动态线程是买药频道应用的技术之一
    的头像 发表于 09-04 11:11 844次阅读
    买药秒送 JADE动态<b class='flag-5'>线程</b><b class='flag-5'>池</b>实践及原理浅析

    卷积神经网络化层的作用

    。其中,化层(Pooling Layer)作为CNN的重要组成部分,在降低模型复杂度、提高计算效率以及增强模型的不变性和鲁棒性方面发挥着关键作用。本文将从多个方面深入探讨化层的作用,力求全面解析其在CNN的核心地位。
    的头像 发表于 07-03 15:58 1693次阅读

    探索虚拟线程:原理与实现

    虚拟线程的引入与优势 在Loom项目之前,Java虚拟机(JVM)线程是通过java.lang.Thread类型来实现的,这些线程被称为平台线程
    的头像 发表于 06-24 11:35 305次阅读
    探索虚拟<b class='flag-5'>线程</b>:原理与实现

    鸿蒙开发:【线程模型】

    管理其他线程的ArkTS引擎实例,例如使用TaskPool(任务)创建任务或取消任务、启动和终止Worker线程
    的头像 发表于 06-13 16:38 410次阅读
    鸿蒙开发:【<b class='flag-5'>线程</b>模型】

    动态线程思想学习及实践

    ://www.javadoop.com/post/java-thread-pool 引言 在后台项目开发过程,我们常常借助线程来实现多线程任务,以此提升系统的吞吐率和响应性;而
    的头像 发表于 06-13 15:43 1189次阅读
    动态<b class='flag-5'>线程</b><b class='flag-5'>池</b>思想学习及实践

    OpenHarmony语言基础类库【@ohos.taskpool(启动任务)】

    建的任务进行如任务执行、任务取消的操作。理论上您可以使用任务API创建数量不受限制的任务,但是出于内存因素不建议您这样做。此外,不建议您在任务执行阻塞操作,特别是无限期阻塞操作,长时间的阻塞操作占据工作线程,可能会阻塞其他任
    的头像 发表于 04-24 17:45 353次阅读
    OpenHarmony语言基础类库【@ohos.taskpool(启动任务<b class='flag-5'>池</b>)】

    java实现多线程的几种方式

    了多种实现多线程的方式,本文将详细介绍以下几种方式: 1.继承Thread类 2.实现Runnable接口 3.Callable和Future 4.线程 5.Java 8
    的头像 发表于 03-14 16:55 708次阅读

    python5种线程锁盘点

    线程安全是多线程或多进程编程的一个概念,在拥有共享数据的多条线程并行执行的程序线程安全的代
    发表于 03-07 11:08 1594次阅读
    python<b class='flag-5'>中</b>5种<b class='flag-5'>线程</b>锁盘点

    基于RTOS的应用进程的典型线程

    RTOS的关键因素是最小的中断延迟和最小的线程切换延迟。RTOS的价值在于它的响应速度或可预测性,而不是它在给定时间段内可以执行的工作量。
    发表于 03-05 09:32 604次阅读
    基于RTOS的应用进程<b class='flag-5'>中</b>的典型<b class='flag-5'>线程</b>

    什么是动态线程?动态线程的简单实现思路

    因此,动态可监控线程一种针对以上痛点开发的线程管理工具。主要可实现功能有:提供对 Spring 应用内线程
    的头像 发表于 02-28 10:42 645次阅读

    线程是什么的基本单位 进程与线程的本质区别

    线程是操作系统处理器调度的基本单位,它代表着独立的执行流。在一个进程,可以包含多个线程,这些线程共享相同的进程资源,如内存空间、文件描述
    的头像 发表于 02-02 16:30 933次阅读

    .NET8性能优化之线程

    目前来说,没有确切的证据证明哪个线程好用,或者效率更高。但是开发者可以使用上面的选项来进行自己的选择,有一个测试就是在Windows线程在比较大的机器上的IO扩展性不太好。如果你的
    的头像 发表于 01-22 14:50 1139次阅读