网易首页 > 网易号 > 正文 申请入驻

不是吧,使用了 Spring Boot 还在自定义线程池?

0
分享至

推荐大家关注一个公众号

后台回复“大礼包”有惊喜礼包!

日英文

Never make somebody your everything, cause when they're gone you've got nothing.

永远不要让某个人成为你的一切,否则他们离开后,你就会一无所有。

每日掏心话

其实一直陪着你的,是那个了不起的自己。任何事情,总有答案。

责编:乐乐 | 来自:blog.csdn.net/m0_37701381/article/details/81072774

往日回顾:

正文


大家好,我是小乐。前言

前两天做项目的时候,想提高一下插入表的性能优化,因为是两张表,先插旧的表,紧接着插新的表,一万多条数据就有点慢了

后面就想到了线程池ThreadPoolExecutor,而用的是Spring Boot项目,可以用Spring提供的对ThreadPoolExecutor封装的线程池ThreadPoolTaskExecutor,直接使用注解启用
使用步骤

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

@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;
}
}

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

> 推荐下自己做的 Spring Cloud 的实战项目:

# 异步线程配置
# 配置核心线程数
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();
}

实现类

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

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

@Autowired
private AsyncService asyncService;

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

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

2018-07-16 22:15:47.655 INFO 10516 --- [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-16 22:15:47.655 INFO 10516 --- [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2018-07-16 22:15:47.770 INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-16 22:15:47.770 INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2018-07-16 22:15:47.816 INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-16 22:15:47.816 INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2018-07-16 22:15:48.833 INFO 10516 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-16 22:15:48.834 INFO 10516 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2018-07-16 22:15:48.986 INFO 10516 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-16 22:15:48.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 * @Date: 2018/7/16/0016 22:19 */
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 Future submit(Callable 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 ListenableFuture submitListenable(Callable task) {
showThreadPoolInfo("2. do submitListenable");
return super.submitListenable(task);
}
}

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

修改ExecutorConfig.javaasyncServiceExecutor方法,将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 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]
2018-07-16 22:23:30.952 INFO 14088 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-16 22:23:30.953 INFO 14088 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2018-07-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]
2018-07-16 22:23:31.353 INFO 14088 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-16 22:23:31.353 INFO 14088 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2018-07-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]
2018-07-16 22:23:31.929 INFO 14088 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-16 22:23:31.930 INFO 14088 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2018-07-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]
2018-07-16 22:23:32.498 INFO 14088 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-16 22:23:32.499 INFO 14088 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync

注意这一行日志:

2018-07-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]

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

你还有什么想要补充的吗?

PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。


版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!

欢迎加入后端架构师,在后台回复“”即可。

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。在这里,我为大家准备了一份2021年最新最全BAT等大厂Java面试经验总结。

别找了,想获取史上最简单的Java大厂面试题学习资料

扫下方二维码回复「面试」就好了

嘿,你在看吗?

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
笑麻了!女子网购裤子裆部现“镂空”设计,商家回应:新潮流!

笑麻了!女子网购裤子裆部现“镂空”设计,商家回应:新潮流!

咖啡店的老板娘
2024-06-14 19:35:03
无耻!金曲奖取消王力宏对李玟致敬的表演,只因他宣传过中国文化

无耻!金曲奖取消王力宏对李玟致敬的表演,只因他宣传过中国文化

综艺拼盘汇
2024-06-16 12:57:49
美的集团员工自爆工资+年终奖收入明细

美的集团员工自爆工资+年终奖收入明细

叮当当科技
2024-06-15 05:21:36
最高37℃!江苏气象最新发布

最高37℃!江苏气象最新发布

荔枝新闻
2024-06-16 12:06:59
“中国技术不如日本?”中国高铁一公里1万度电,日本只要43度?

“中国技术不如日本?”中国高铁一公里1万度电,日本只要43度?

番茄说史聊
2024-06-15 22:01:17
湖人新目标来了?24岁眼镜哥将成为自由球员 队记回应薪水是关键

湖人新目标来了?24岁眼镜哥将成为自由球员 队记回应薪水是关键

罗说NBA
2024-06-16 06:58:42
沙特终止与美石油美元协议

沙特终止与美石油美元协议

参考消息
2024-06-15 19:01:11
中国海军为何不能去古巴?专家给出答案

中国海军为何不能去古巴?专家给出答案

青年的背包
2024-06-16 00:10:09
中国物理学之父,娶重病、不育的师妹:没有她,功名再大也无意义

中国物理学之父,娶重病、不育的师妹:没有她,功名再大也无意义

紫衫书舍
2024-06-14 19:06:31
是什么让发展中国家毫无翻身希望?

是什么让发展中国家毫无翻身希望?

智先生
2024-06-15 21:04:01
蔚来总裁:电池寿命也就15年,但蔚来车主可通过换电实现电池永生

蔚来总裁:电池寿命也就15年,但蔚来车主可通过换电实现电池永生

映射生活的身影
2024-06-15 10:56:12
才两年!国产手机使用韩国OLED面板的比例从77.9%暴跌至16%

才两年!国产手机使用韩国OLED面板的比例从77.9%暴跌至16%

最潮家居评
2024-06-16 05:27:40
大陆打到台痛处,沉默10天后,一架专机直飞北京,要求手下留情

大陆打到台痛处,沉默10天后,一架专机直飞北京,要求手下留情

影孖看世界
2024-06-15 18:38:50
乌军第42旅在哈尓科夫方向损失惨重引发军人家属激烈反应

乌军第42旅在哈尓科夫方向损失惨重引发军人家属激烈反应

大胖说科普
2024-06-16 12:28:45
指挥所遭空袭,数十人被埋!这次偷袭俄本土的不明战机是F-35吗?

指挥所遭空袭,数十人被埋!这次偷袭俄本土的不明战机是F-35吗?

锋芒毕露
2024-06-16 12:24:54
那个美国老师说!

那个美国老师说!

吴女士
2024-06-14 09:52:41
缅北女魔头魏榕,帅哥真实自述:把我关进狗笼,我口腔感染了3次

缅北女魔头魏榕,帅哥真实自述:把我关进狗笼,我口腔感染了3次

马尔科故事会
2024-06-15 11:51:34
“税务倒查30年”孰是孰非,看一下法律依据是什么,不妨讨论一下

“税务倒查30年”孰是孰非,看一下法律依据是什么,不妨讨论一下

涛涛生活搞笑
2024-06-15 17:56:11
以色列引以为傲的铁穹,被电磁脉冲武器干趴,紧急呼叫美国爸爸

以色列引以为傲的铁穹,被电磁脉冲武器干趴,紧急呼叫美国爸爸

青年的背包
2024-06-16 12:56:53
不是周琦,不是张镇麟,中国男篮最新队长曝光,辽宁队球迷破防了

不是周琦,不是张镇麟,中国男篮最新队长曝光,辽宁队球迷破防了

宗介说体育
2024-06-15 14:03:02
2024-06-16 13:40:49
程序员小乐
程序员小乐
有趣有内涵
3163文章数 9493关注度
往期回顾 全部

科技要闻

iPhone 16会杀死大模型APP吗?

头条要闻

上海一家三口出动去香港过周末 在高铁动卧睡一晚就到

头条要闻

上海一家三口出动去香港过周末 在高铁动卧睡一晚就到

体育要闻

没人永远年轻 但青春如此无敌还是离谱了些

娱乐要闻

上影节红毯:倪妮好松弛,娜扎吸睛

财经要闻

打断妻子多根肋骨 上市公司创始人被公诉

汽车要闻

售17.68万-21.68万元 极狐阿尔法S5正式上市

态度原创

健康
艺术
家居
亲子
数码

晚餐不吃or吃七分饱,哪种更减肥?

艺术要闻

穿越时空的艺术:《马可·波罗》AI沉浸影片探索人类文明

家居要闻

空谷来音 朴素留白的侘寂之美

亲子要闻

陪宝宝看鲨鱼,跟海底动物们来个亲密接触,就差美人鱼了

数码要闻

优派 XG323-4K-OLED-2 显示器预告:原生 10bit、全功能 Type-C

无障碍浏览 进入关怀版