Java打怪之路----谷粒商场异步编排

一、异步复习

创造线程的四种方式

  1. 继承Thread类
    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:" + i);
        }
    }
    public static void main(String[] args){
    	Thread thread=new Thread01();
    	thread.start();		
    }
    
  1. 实现Runnable接口
    public static class Runable01 implements Runnable {
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:" + i);
        }
    }
      public static void main(String[] args){
    	 Runable01 r=new Runable01();
    	new Thread(r).start;
    }
  1. 实现Callable接口

    public static class Callable01 implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:" + i);
            return i;
        }
    }
     public static void main(String[] args){
    	 FutureTask <Integer> fu= new FutureTask <>(new Callable01();
    	new Thread(fu).start;
    }
  1. 线程池
public static ExecutorService executor = Executors.newFixedThreadPool(10);

1.1线程池详解(ExecutorService)

为什么要使用线程池:通过1,2,3方式获取线程无法控制资源。当有多个异步任务时,1,2,3方式就会创造多个线程,这会占用极大的内存空间。当前主机如果只有1g资源只能同时执行200个线程,那么就创造200个线程的线程池,每次只有200个线程同时执行,达到了控制资源的效果。

线程池的创建方式

(1)使用Executors

public static ExecutorService executor = Executors.newFixedThreadPool(10);

(2)new ThreadPoolExecutor();

 private static void threadPool() {

        ExecutorService threadPool = new ThreadPoolExecutor(
                200,
                10,
                10L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<Runnable>(10000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );

        //定时任务的线程池
        ExecutorService service = Executors.newScheduledThreadPool(2);
    }

七大参数

  • corePoolSIze:核心线程数,线程池创建之后就准备
  • maximumPoolSize:最大线程数量,在核心线程池满了之后可以容纳的最大的线程数量
  • keepAliveTime:当线程数量大于核心线程数,该值控制线程在多久后终止释放
  • unit:keepAliveTime时间单位
  • workQueue:阻塞队列,用来存储等待执行的任务,如果执行的线程数大于核心线程数,就会被送入阻塞队列阻塞。
  • threadFactory:创建线程的工厂
  • handler:拒绝策略,如果线程满了线程池采用的拒绝策略

ThreadPoolExecutor的运行流程

  • (1)线程池创建好,准备好核心线程数,等待任务执行
  • (2)任务开始执行,首先核心线程数准备好的线程进行执行
    - 如果核心线程数满了,就会将未执行的线程送入阻塞队列进行阻塞
    - 如果阻塞队列满了,就会根据最大线程数量开辟线程
    - 如果开辟的最大线程数量仍少于请求的线程数,剩下的线程将会被拒绝。

线程池使用的好处

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

二、CompletableFuture 异步编排

业务场景:
查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间。
在这里插入图片描述

假如商品详情页的每个查询,需要如下标注的时间才能完成
那么,用户需要5.5s 后才能看到商品详情页的内容。很显然是不能接受的。
如果有多个线程同时完成这6 步操作,也许只需要1.5s 即可完成响应。

如果开辟6个线程同时执行时不行的,2,3,4,5号业务就需要在1号业务执行完成之后才能执行(获取sku信息之后才能获取到spu信息)。所以CompletableFuture可以用来进行异步编排

三、CompletableFuture 异步编排在项目中的使用

创建线程池

@EnableConfigurationProperties(ThreadPoolConfigProperties.class)//开启ThreadPoolConfigProperties的自动配置
@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()
        );
    }
}

异步任务
sku基本属性获取完,才能获取到spu相关的属性,所以关于spu相关属性的获取需要在sku基本属性获取完之后执行
sku基本信息的获取---->spu的销售属性组合获取---->获取spu的介绍---->获取spu的规格参数信息
sku的图片信息单独执行

@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.getSaleAttrBySpuId(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);


        // Long spuId = info.getSpuId();
        // Long catalogId = info.getCatalogId();

        //2、sku的图片信息    pms_sku_images
        CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
            List<SkuImagesEntity> imagesEntities = skuImagesService.getImagesBySkuId(skuId);
            skuItemVo.setImages(imagesEntities);
        }, executor);
                //等到所有任务都完成
        	CompletableFuture.allOf(saleAttrFuture,descFuture,baseAttrFuture,imageFuture,seckillFuture).get();

        return skuItemVo;
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值