1,线程池配置类
package com.june.mall.product.config;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
//@EnableConfigurationProperties(ThreadPoolConfigProperties.class) //如果ThreadPoolConfigProperties类没有放入spring容器(@Component注解),那么要添加此注解
@Configuration
public class MyThreadConfig {
@Bean
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties myProperties) {
return new ThreadPoolExecutor(myProperties.getCoreSize(), //核心线程数量。这些线程一直存在
myProperties.getMaxSize(), //最大线程数。允许得最大线程数
myProperties.getKeepAliveTime(), //空闲线程存活时间。当没有任务时,空闲线程可存活时间
TimeUnit.SECONDS, // 空闲线程存活时间的单位
new LinkedBlockingDeque<>(100000), //线程队列(设置最大容量十万个)。当线程数大于{核心线程数量}时,其他线程进入队列
Executors.defaultThreadFactory(), //线程工厂
new ThreadPoolExecutor.AbortPolicy()); //当超过{最大线程数}时,采取的拒绝策略。 根据自己需求配置拒绝策略
}
}
2,线程池配置类的参数配置类。(也可以不写这个类,直接用@value注解动态获取值)
package com.june.mall.product.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Data;
@ConfigurationProperties(prefix = "mall.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
private Integer coreSize;
private Integer maxSize;
private Integer keepAliveTime;
}
3,application.properties 根据自己需求配置
mall.thread.core-size=20
mall.thread.max-size=200
mall.thread.keep-alive-time=10
4,代码中使用
异步编排
异步编排
例如在某个 service 中(如京东商品详情页)
目的:要获取商品基本信息,还有获取商品图片,还要获取介绍信息,还要获取参数信息,评论信息等等。
■如果使用传统的写法,则:先去数据库基本信息,然后查图片信息,然后查…。显然这样让一个线程去执行,比较耗时。
■采用异步编排,则:开一个线程先去数据库基本信息(因为后面要依赖基本信息如id,获取其他信息),
获取到基本信息后
,再开一个线程获取介绍【此时可同时开一个线程获取介绍信息,开一个线程获取参数信息…】。 (如果不依赖基本信息的话,可以直接开一个线程获取需要的信息。如最后的图片获取)
异步编排优化
public class productServiceImpl {
//导入刚配置的线程池
@Autowired
private ThreadPoolExecutor executor;
// 此方法通过商品id 获取商品详情页所需要的信息
public Product item(Long skuId) throws Exception {
Product vo = new Product ();
//1,先获取基本信息
CompletableFuture<SkuInfoEntity> baseInfoFuturn = CompletableFuture.supplyAsync(() -> {
//从数据库查询基本信息并返回
SkuInfoEntity info = getById(skuId);
vo.setInfo(info);
return info;
}, executor);
// 2,在基本信息获取后 baseInfoFuturn 的基础上,再获取属性信息。此时不需要返回值
// thenAcceptAsync 方法接收参数,但不返回值
CompletableFuture<Void> saleAttrFuture = baseInfoFuturn.thenAcceptAsync((res) -> {
Long spuId = res.getSpuId();
List<SkuItemSaleAttrVo> SkuItemSaleAttrVos = skuSaleAttrValueService
.getSaleAttrsBySpuId(spuId);
vo.setSaleAttrs(SkuItemSaleAttrVos);
}, executor);
// 3,介绍信息。类似 第二步
CompletableFuture<Void> descFuture = baseInfoFuturn.thenAcceptAsync((res) -> {
SpuInfoDescEntity spuInfo = infoDescService.getById(res.getSpuId());
vo.setDesp(spuInfo);
}, executor);
// 4,图片信息 因为不依赖基本信息,所有 直接 CompletableFuture 执行
//runAsync 方法开启一个线程直接执行方法,也不返回值
CompletableFuture<Void> imgFuture = CompletableFuture.runAsync(() -> {
List<SkuImagesEntity> imgs = imagesService.getImagesBySkuId(skuId);
vo.setImages(imgs);
}, executor);
// 必须等待所有异步任务执行完成才能返回结果
CompletableFuture.allOf(saleAttrFuture, descFuture, imgFuture).get();
return vo;
}
}
版权声明:本文为weixin_43530295原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。