线程池配置
package com.fast.boot.framework.config;
import com.fast.boot.common.config.ThreadPoolProperties;
import com.fast.boot.common.utils.ThreadsUtils;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
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;
import javax.annotation.Resource;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池配置
*
* @author ming
* @date 2023-01-03 10:51
**/
@EnableAsync // 开启异步
@Configuration
@EnableConfigurationProperties(value = ThreadPoolProperties.class)
public class ThreadPoolConfig {
@Resource
private ThreadPoolProperties threadPoolProperties;
@Bean(name = "threadPoolTaskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix(threadPoolProperties.getThreadCustomPrefix());
executor.setCorePoolSize(threadPoolProperties.getCorePoolSize());
executor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize());
executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
// 线程池对拒绝任务(无线程可用)的处理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
/*
tasks :每秒的任务数,假设为500~1000
taskcost:每个任务花费时间,假设为0.1s
responsetime:系统允许容忍的最大响应时间,假设为1s
做几个计算
corePoolSize = 每秒需要多少个线程处理?
threadcount = tasks/(1/taskcost) = tasks*taskcout = (500 ~ 1000)*0.1 = 50~100 个线程。
corePoolSize设置应该大于50。
根据8020原则,如果80%的每秒任务数小于800,那么corePoolSize设置为80即可。
queueCapacity = (coreSizePool/taskcost)responsetime
*/
/**
* 执行周期性或定时任务
*/
@Bean(name = "scheduledExecutorService")
protected ScheduledExecutorService scheduledExecutorService() {
return new ScheduledThreadPoolExecutor(threadPoolProperties.getCorePoolSize(),
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
new ThreadPoolExecutor.CallerRunsPolicy()) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
ThreadsUtils.printException(r, t);
}
};
}
}
模拟测试
package com.fast.boot.web.controller.common;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSON;
import com.fast.boot.common.annotation.GlobalResult;
import com.fast.boot.mail.service.MailService;
import com.fast.boot.model.AjaxResult;
import com.fast.boot.model.Result;
import com.fast.boot.service.sdk.CommonService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
/**
* 通用请求处理
*
* @author ming
* @date 2022-12-27 18:56
*/
@RestController
@RequestMapping("/common")
@RequiredArgsConstructor
@Slf4j
public class CommonController {
@Resource
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@ApiOperation(value = "测试接口")
@GetMapping("test")
public AjaxResult<?> test(String key, Integer len) {
log.info("测试 :{}", key);
test(len);
return AjaxResult.success("测试");
}
@ApiOperation(value = "测试接口3")
@GetMapping("test3")
@GlobalResult
public Integer test3(String key, Integer count) {
log.info("异步测试 :{}", key);
List<String> searchList = new ArrayList<>();
for (int i = 0; i < count; i++) {
searchList.add(System.currentTimeMillis() + "" + i);
}
List<Callable<Map<String, Object>>> tasks = searchList.stream()
.map(item -> (Callable<Map<String, Object>>) () -> buildResultMap(item))
.collect(Collectors.toList());
List<Map<String, Object>> res = execQuery(tasks);
log.info("test3异步结果:" + JSON.toJSONString(res));
return 3;
}
public void test(Integer count) {
log.info("执行并行、串行测试: count=" + count);
// 并行流测试
List<Long> searchList = new ArrayList<>();
for (long i = count; i > 0; i--) {
searchList.add(System.currentTimeMillis() + i);
}
long asyncStart = System.currentTimeMillis();
List<String> completableFutureList = searchList.parallelStream()
.map(first -> CompletableFuture.supplyAsync(() -> getSearchResult(first), threadPoolTaskExecutor))
.map(second -> second.thenApply(this::queryB))
.map(third -> third.thenApply(this::queryB))
.map(CompletableFuture::join)
.filter(Objects::nonNull)
.collect(Collectors.toList());
long elapsedTime = System.currentTimeMillis() - asyncStart;
log.info("并行:" + elapsedTime);
// completableFutureList.forEach(System.out::println);
asyncStart = System.currentTimeMillis();
List<String> completableFutureList2 = searchList.parallelStream()
.map(this::getSearchResult)
.map(this::queryB)
.map(this::queryB)
.filter(Objects::nonNull)
.collect(Collectors.toList());
elapsedTime = System.currentTimeMillis() - asyncStart;
log.info("串行:" + elapsedTime);
// completableFutureList2.forEach(System.out::println);
// CompletableFuture.supplyAsync().thenApply() 使用上一步的结果继续执行,使用的线程池类型不同ExecutorService executorService = Executors.newSingleThreadExecutor();
}
public String getSearchResult(long orderId) {
// 模拟外部接口耗时
ThreadUtil.safeSleep(50);
//do some your business
return "getSearchResult--测试:" + orderId;
}
public String queryB(String s) {
// 模拟外部接口耗时
ThreadUtil.safeSleep(50);
return "queryB" + s;
}
/**
* 异步执行(实际效果比parallelStream更优)
*
* @param tasks 异步任务
* @return java.util.List<java.lang.Object>
* @author ext.wenzhongming1
* @since 2023/2/3 11:17
*/
protected <U> List<U> execQuery(List<Callable<U>> tasks) {
try {
List<Future<U>> results = threadPoolTaskExecutor.getThreadPoolExecutor().invokeAll(tasks);
return results.stream().map(item -> {
try {
return item.get();
} catch (Exception e) {
log.error("【execQuery】异步执行结果获取异常", e);
}
return null;
}).collect(Collectors.toList());
} catch (Exception e) {
log.error("【execQuery】异步执行异常", e);
}
return Collections.emptyList();
}
/**
* 需要异步的业务代码,模拟接口耗时
*
* @param s 入参
* @return java.util.Map<java.lang.String, java.lang.Object>
* @author ext.wenzhongming1
* @since 2023/2/6 10:24
*/
private Map<String, Object> buildResultMap(String s) {
Map<String, Object> map = new HashMap<>();
map.put("testId", s);
ThreadUtil.safeSleep(RandomUtil.randomInt(100));
return map;
}
}