Java 异步编排-简单使用

  • Post author:
  • Post category:java




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 版权协议,转载请附上原文出处链接和本声明。