0. CompletableFuture
0.1 创建异步对象
CompletableFuture 提供了四个静态方法来创建一个异步操作。
1、 runXxxx 都是没有返回结果的, supplyXxx 都是可以获取返回结果的;
2、 Executor是线程池参数。可以传入自定义的线程池, 否则就用默认的线程池;
0.2 计算完成时回调方法
whenComplete 可以处理正常和异常的计算结果, exceptionally 处理异常情况。
whenComplete 和 whenCompleteAsync 的区别:
whenComplete: 是执行当前任务的线程执行继续执行 whenComplete 的任务。
whenCompleteAsync: 是执行把 whenCompleteAsync 这个任务继续提交给线程池
来进行执行。
方法不以 Async 结尾, 意味着 Action 使用相同的线程执行, 而 Async 可能会使用其他线程
执行(如果是使用相同的线程池, 也可能会被同一个线程选中执行)
0.3 handle 方法
和 complete 一样, 可对结果做最后的处理(可处理异常) , 可改变返回值。
whenComplete 和 handle 对比:
whenComplete:不消费异常,不可改变返回值。
handle: 消费异常,可改变返回值。
两者的重要区别在于handle可进行结果的“替换”。如果handle可以把“异常”替换为一个正常结果,那么可以视作handle“消费”了异常。
0.4 线程串行化方法
thenApply: 当一个线程依赖另一个线程时, 获取上一个任务返回的结果, 并返回当前
任务的返回值。apply有“申请”、“应用”的意思,我个人理解为把上一个线程的结果“应用于”下一个线程的计算。相当于结果值的传递。
Function<? super T,? extends U>
T: 上一个任务返回结果的类型
U: 当前任务的返回值类型
thenAccept : 消费处理结果。 接收任务的处理结果, 并消费处理, 无返回结果。thenAccept 同 thenApply 接收上一个任务的返回值作为参数,但是回调方法无返回值。
thenRun : 只要上面的任务执行完成, 就开始执行 thenRun, 只是处理完任务后, 执行
thenRun 的后续操作。thenRun 是上一个任务完成后触发的回调,没有入参,也没有返回值。
带有 Async 默认是异步执行的。 同之前。以上都要前置任务成功完成。
thenApply,thenAccept,thenRun的区别如下:
0.5 组合任务
0.5.1 两任务组合 - 都要完成:两个任务必须都完成, 触发该任务。
thenCombine: 组合两个 future, 获取两个 future 的返回结果, 并返回当前任务的返回值。有入参,有返回值。
thenAcceptBoth: 组合两个 future, 获取两个 future 任务的返回结果, 然后处理任务, 没有
返回值。有入参,无返回值。
runAfterBoth: 组合两个 future, 不需要获取 future 的结果, 只需两个 future 处理完任务后,
处理该任务。无入参,无返回值。
0.5.2 两任务组合 - 一个完成:当两个任务中, 任意一个 future 任务完成的时候, 执行任务。
applyToEither: 两个任务有一个执行完成, 获取它的返回值, 处理任务并有新的返回值。有入参,有返回值。
acceptEither: 两个任务有一个执行完成, 获取它的返回值, 处理任务, 没有新的返回值。有入参,无返回值。
runAfterEither: 两个任务有一个执行完成, 不需要获取 future 的结果, 处理任务, 也没有返
回值。无入参,无返回值。
0.5.3 多任务组合
allOf: 等待所有任务完成
anyOf: 只要有一个任务完成
1. config
MyThreadConfig.java
package com.atguigu.gulimall.product.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
//@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
@Configuration
public class MyThreadConfig {
@Bean
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool){
return new ThreadPoolExecutor(pool.getCoreSize(), pool.getMaxSize(), pool.getKeepAliveTime(), TimeUnit.SECONDS,new LinkedBlockingDeque<>(100000), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
}
}
ThreadPoolConfigProperties.java
package com.atguigu.gulimall.product.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
//可以配置属性
@ConfigurationProperties(prefix = "gulimall.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
private Integer coreSize;
private Integer maxSize;
private Integer keepAliveTime;
}
application.properties
gulimall.thread.core-size=20
gulimall.thread.max-size=200
gulimall.thread.keep-alive-time=10
2. Controller
ItemController.java
package com.atguigu.gulimall.product.web;
import com.atguigu.gulimall.product.service.SkuInfoService;
import com.atguigu.gulimall.product.vo.SkuItemVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.concurrent.ExecutionException;
@Controller
public class ItemController {
@Autowired
SkuInfoService skuInfoService;
//展示当前sku详情
@GetMapping("/{skuId}.html")
public String skuItem(@PathVariable("skuId") Long skuId, Model model) throws ExecutionException, InterruptedException {
System.out.println(skuId);
SkuItemVo vo = skuInfoService.item(skuId);
model.addAttribute("item",vo);
return "item";
}
}
3. Service
SkuInfoService.java
package com.atguigu.gulimall.product.service;
import com.atguigu.gulimall.product.vo.SkuItemVo;
import com.baomidou.mybatisplus.extension.service.IService;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.gulimall.product.entity.SkuInfoEntity;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
/**
* sku信息
*
* @author jude
* @email sunlightcs@gmail.com
* @date 2022-08-24 13:21:08
*/
public interface SkuInfoService extends IService<SkuInfoEntity> {
SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException;
}
SkuInfoServiceImpl.java
package com.atguigu.gulimall.product.service.impl;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.product.entity.SkuImagesEntity;
import com.atguigu.gulimall.product.entity.SpuInfoDescEntity;
import com.atguigu.gulimall.product.feign.SeckillFeignService;
import com.atguigu.gulimall.product.service.*;
import com.atguigu.gulimall.product.vo.SeckillSkuVo;
import com.atguigu.gulimall.product.vo.SkuItemSaleAttrVo;
import com.atguigu.gulimall.product.vo.SkuItemVo;
import com.atguigu.gulimall.product.vo.SpuItemAttrGroupVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;
import com.atguigu.gulimall.product.dao.SkuInfoDao;
import com.atguigu.gulimall.product.entity.SkuInfoEntity;
import org.springframework.util.StringUtils;
@Service("skuInfoService")
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoDao, SkuInfoEntity> implements SkuInfoService {
@Autowired
SkuImagesService imagesService;
@Autowired
SpuInfoDescService spuInfoDescService;
@Autowired
SkuSaleAttrValueService skuSaleAttrValueService;
@Autowired
AttrGroupService attrGroupService;
@Autowired
ThreadPoolExecutor executor;
@Autowired
private SeckillFeignService seckillFeignService;
@Override
public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
SkuItemVo skuItemVo = new SkuItemVo();
CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
//1、sku基本信息的获取 pms_sku_info
SkuInfoEntity info = this.getById(skuId);
skuItemVo.setInfo(info);
return info;
}, executor);
CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync((res) -> {
//3、获取spu的销售属性组合
List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrsBySpuId(res.getSpuId());
skuItemVo.setSaleAttr(saleAttrVos);
}, executor);
CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync((res) -> {
//4、获取spu的介绍 pms_spu_info_desc
SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(res.getSpuId());
skuItemVo.setDesc(spuInfoDescEntity);
}, executor);
CompletableFuture<Void> baseAttrFuture = infoFuture.thenAcceptAsync((res) -> {
//5、获取spu的规格参数信息
List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
skuItemVo.setGroupAttrs(attrGroupVos);
}, executor);
//2、sku的图片信息 pms_sku_images
CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
List<SkuImagesEntity> imagesEntities = imagesService.getImagesBySkuId(skuId);
skuItemVo.setImages(imagesEntities);
}, executor);
CompletableFuture<Void> seckillFuture = CompletableFuture.runAsync(() -> {
//3、远程调用查询当前sku是否参与秒杀优惠活动
R skuSeckilInfo = seckillFeignService.getSkuSeckilInfo(skuId);
if (skuSeckilInfo.getCode() == 0) {
//查询成功
SeckillSkuVo seckilInfoData = skuSeckilInfo.getData("data", new TypeReference<SeckillSkuVo>() {
});
skuItemVo.setSeckillSkuVo(seckilInfoData);
if (seckilInfoData != null) {
long currentTime = System.currentTimeMillis();
if (currentTime > seckilInfoData.getEndTime()) {
skuItemVo.setSeckillSkuVo(null);
}
}
}
}, executor);
//等到所有任务都完成
CompletableFuture.allOf(saleAttrFuture,descFuture,baseAttrFuture,imageFuture,seckillFuture).get();
return skuItemVo;
}
}