【Gulimall+】异步编排 & 线程池

线程回顾

参见link
通过如下两种方式初始化线程池

Executors.newFixedThreadPool(3);
//或者
new ThreadPollExecutor(corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit,unit,workQueue,threadFactory,handler);

通过线程池性能稳定,也可以获取执行结果,并捕获异常,但是,在业务复杂情况下,一个异步调用可能会依赖另一个异步调用的执行结果

线程池的 7 大参数

1、线程池创建,准备好 core 数量 的核心线程,准备接受任务
2、新的任务进来,用 core 准备好的空闲线程执行
    core 满了,就将再进来的任务放入阻塞队列中,空闲的 core 就会自己去阻塞队列获取任务执行
    阻塞队列也满了,就直接开新线程去执行,最大只能开到 max 指定的数量
    max 都执行好了,Max-core 数量空闲的线程会在 keepAliveTime 指定的时间后自动销毁,终保持到 core 大小
    如果线程数开到了 max 数量,还有新的任务进来,就会使用 reject 指定的拒绝策略进行处理
3、所有的线程创建都是由指定的 factory 创建的

面试;
一个线程池 core 7、max 20 ,queue 50 100 并发进来怎么分配的 ?
先有 7 个能直接得到运行,接下来 50 个进入队列排队,再多开 13 个继续执行,线程70个被安排上了,剩下30个默认拒绝策略

常见的 4 种线程池

newCacheThreadPool 创建一个可缓存的线程池,如果线程池长度超过需要,可灵活回收空闲线程,若无可回收,则新建线程
newFixedThreadPool 创建一个指定长度的线程池,可控制线程最大并发数,超出的线程会再队列中等待
newScheduleThreadPool 创建一个定长线程池,支持定时及周期性任务执行
newSingleThreadExecutor 创建一个单线程化的线程池,她只会用唯一的工作线程来执行任务,保证所有任务

开发中为什么使用线程池

降低资源的消耗
    通过重复利用已创建好的线程降低线程的创建和销毁带来的损耗
提高响应速度
    因为线程池中的线程没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行
提高线程的客观理性
    线程池会根据当前系统的特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销,无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配

CompletableFuture 异步编排

创建异步对象

CompletableFuture 提供了四个静态方法来创建一个异步操作
1、runXxx 都是没有返回结果的,supplyXxxx都是可以获取返回结果的
2、可以传入自定义的线程池,否则就是用默认的线程池
3、根据方法的返回类型来判断是否该方法是否有返回类型

计算完成时回调方法

whenComplete 可以处理正常和异常的计算结果,exceptionally 处理异常情况
whenComplete 和 whenCompleteAsync 的区别
​ whenComplete :是执行当前任务的线程继续执行 whencomplete 的任务
​ whenCompleteAsync: 是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行
方法不以 Async 结尾,意味着 Action 使用相同的线程执行,而 Async 可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)

handle 方法

和 complete 一样,可以对结果做最后的处理(可处理异常),可改变返回值

线程串行方法

thenApply 方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任物的返回值
thenAccept方法:消费处理结果,接受任务处理结果,并消费处理,无返回结果
thenRun 方法:只要上面任务执行完成,就开始执行 thenRun ,只是处理完任务后,执行 thenRun的后续操作
带有 Async 默认是异步执行的,同之前,

两任务组合 - 都要完成

两个任务必须都完成,触发该任务
thenCombine: 组合两个 future,获取两个 future的返回结果,并返回当前任务的返回值
thenAccpetBoth: 组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有返回值
runAfterBoth:组合 两个 future,不需要获取 future 的结果,只需要两个 future处理完成任务后,处理该任务,

两任务组合 - 一个完成

当两个任务中,任意一个future 任务完成时,执行任务
applyToEither;两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值
acceptEither: 两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值
runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返回值

多任务组合

allOf:等待所有任务完成
anyOf:只要有一个任务完成

商品详情获取

发生在item.html

com/atguigu/gulimall/product/service/impl/SkuInfoServiceImpl.java

    @Autowired
    ThreadPoolExecutor executor; //线程池

    @Override
    public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
        SkuItemVo skuItemVo = new SkuItemVo();

        CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
            // 1、sku基本获取 pms_sku_info
            // 根据 skuid 查询出 spuInfo对象
            SkuInfoEntity info = getById(skuId);
            skuItemVo.setSkuInfo(info);
            return info;
        }, executor);

        CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync((res) -> {
            Long spuId = res.getSpuId();
            // 3、获取spu的销售属性组合
            List<SkuItemSalAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrBySpuId(spuId);
            skuItemVo.setSaleAttr(saleAttrVos);
        }, executor);


        CompletableFuture<Void> spuDescFuture = infoFuture.thenAcceptAsync((res) -> {
            Long spuId = res.getSpuId();
            // 4、获取spu的介绍
            // 通过spuid查询出spu描述信息

            SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(spuId);
            skuItemVo.setDesc(spuInfoDescEntity);

        }, executor);

        CompletableFuture<Void> spuAttrFuture = infoFuture.thenAcceptAsync(res -> {
            // 5、获取spu的规格参数信息
            List<SpuItemAttrGroupVo> spuItemAttrGroupVoList = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
            skuItemVo.setGroupAttrs(spuItemAttrGroupVoList);
        }, executor);


        CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
            // 2、sku的图片信息 pms_sku_images
            List<SkuImagesEntity> images = imagesService.getImagesBySkuId(skuId);
            skuItemVo.setImages(images);
        }, executor);

        //3.查询当前商品是否参与秒杀
        CompletableFuture<Void> seckillFuture = CompletableFuture.runAsync(() -> {
            R r = seckillFeignService.getSkuSeckillInfo(skuId);
            if (r.getCode() == 0) {
                SeckillInfoVo seckillInfoVo = r.getData("data", new TypeReference<SeckillInfoVo>() {
                });
                skuItemVo.setSeckillInfoVo(seckillInfoVo);
            }
        }, executor);

        //等到所有任务都完成
        CompletableFuture.allOf(imageFuture, saleAttrFuture, spuAttrFuture, spuDescFuture,seckillFuture).get();

        return skuItemVo;
    }

自定义线程池配置类

com/atguigu/gulimall/product/config/MyThreadConfig.java

@Configuration
public class MyThreadConfig {

    @Bean
    public ThreadPoolExecutor genThreadPool(ThreadPoolConfigProperties pool) { //由于ThreadPoolConfigProperties pool已经放入IOC,所以这儿会自动注入参数
        return new ThreadPoolExecutor(pool.getCoreSize(), pool.getMaxSize(), pool.getKeepLiveTime(),
                TimeUnit.SECONDS, new LinkedBlockingDeque<>(100000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
    }
}

看看ThreadPoolConfigProperties这个是啥,结果又卖了一个官司

@ConfigurationProperties(prefix = "gulimall.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
    private Integer coreSize;
    private Integer maxSize;
    private Integer keepLiveTime;
}

去配置文件application.properties看看

gulimall.thread.core-size=20
gulimall.thread.max-size=200
gulimall.thread.keep-live-time=10

是不是和prefix = "gulimall.thread"很一致,为了在配置文件中键入时有提示,导入依赖

        <!--在application.properties中配置自定义配置类时,提示需要配置的内容-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星空•物语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值