多线程

一、初始化线程的4种方式

1)、继承Thread

2)、实现Runnable接口

3)、实现Callable接口 + FutureTask(可以拿到返回结果,可以处理异常)

4)、线程池

方式1和方式2;主线程无法获取线程的运算结果,不适合当前场景

方式3:主线程可以获取线程的运算结果,但是不利于控制服务器中的线程资源,可以导致服务器耗尽

方式4:

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

//@EnableConfigurationProperties(ThreadPoolProperties.class)
@Configuration
public class MyThreadConfig {

@Bean
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolProperties pool) {
return new ThreadPoolExecutor(
pool.getCoreSize(),
pool.getMaxSize(),
pool.getKeepAliveTime(),
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(100000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
}
}

二、开发中为什么使用线程池

1)、降低资源的消耗

通过重复利用已经建好的线程降低线程的创建和销毁带夹得损耗

2)、提高响应速度

因为线程池中得线程数没有超过线程池得最大上限时,有得线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行

3)、提高线程的可管理性

线程池根据当前线程的特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销,无线的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配

三、CompletableFuture异步编排

1)CompletableFuture 提供了四个静态方法来创建一个异步操作

public static CompletableFuture runAsync(Runnable runnable)
public static CompletableFuture runAsync(Runnable runnable, Executor executor)
public static CompletableFuture supplyAsync(Supplier supplier)
public static CompletableFuture supplyAsync(Supplier supplier, Executor executor)

没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同
a: runAsync方法不支持返回值。
b: supplyAsync可以支持返回值。
c: 可以传入自定义的线程池,否则使用默认的线程池

2) 计算结果完成时的回调方法

//可以处理异常,无返回值
public CompletableFuture whenComplete(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
//可以处理异常,有返回值
public CompletableFuture exceptionally(Function<Throwable,? extends T> fn)

a、whenComplete:可以处理正常和异常的计算结果;exceptionally:处理异常情况
b、whenComplete 和 whenCompleteAsync 的区别
whenComplete :是当前线程任务执行完后继续执行 whenComplete 中的任务
whenCompleteAsync :是把 whenCompleteAsync 这个任务继续提交给线程池来执行

c、方法不以 Async 结尾,意味着Actiuon使用的是相同的线程执行,而 Async可能使用其他线程执行【如果使用相同的线程池,也可能会被同一个线程所选中】

四、线程串行化

a、thenRun:不能获取上一步的执行结果
b、thenAcceptAsync:能接受上一步结果,但是无返回值
c、thenApplyAsync:能接受上一步结果,并有返回值,传递给下一步

五、两任务组合

1)、thenCombine 会把 两个 CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 来处理

public <U,V> CompletionStage thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor)

2)、thenAcceptBoth:当两个CompletionStage都执行完成后,把结果一块交给thenAcceptBoth来进行消耗

public CompletionStage thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
public CompletionStage thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
public CompletionStage thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor);

3)、runAfterBoth:两个CompletionStage,都完成了计算才会执行下一步的操作(Runnable)

public CompletionStage runAfterBoth(CompletionStage other,Runnable action); public CompletionStage runAfterBothAsync(CompletionStage other,Runnable action);
public CompletionStage runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor

a、thenCombine :组合两个 future,获取两个future 的返回结果,并返回当前任务的返回值

b、thenAcceptBoth :组合两个 future,获取两个future 的返回结果,然后处理任务,没有返回值

c、runAfterBoth :组合两个 future,不需要获取future的结果,只需要两个future处理完后任务后,处理该任务

4)、applyToEither : 当两个任务中,任意一个future完成的时候,执行任务

六、多任务组合

a、allof:等待所有的任务执行完

b、anyof:只要有一个线程完成

七、运用的实例

/**
* 前台查询商品详情页信息 - 加入异步编排
* @param skuId
* @return
*/
@Override
public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {

SkuItemVo skuItemVo = new SkuItemVo();

// supplyAsync 需要返回结果 因为 3 4 5 依赖1
CompletableFuture infoFuture = CompletableFuture.supplyAsync(() -> {
// 1、获取sku基本信息 pms_sku_info
SkuInfoEntity skuInfoEntity = getById(skuId);
skuItemVo.setInfo(skuInfoEntity);
return skuInfoEntity;
}, executor);

CompletableFuture saleFuture = infoFuture.thenAcceptAsync((res) -> {
// 3、获取spu的销售属性组合
List skuItemSaleAttrVos = skuSaleAttrValueService.getSaleAttrsBySpuId(res.getSpuId());
skuItemVo.setSaleAttrs(skuItemSaleAttrVos);
}, executor);

CompletableFuture descFuture = infoFuture.thenAcceptAsync((res) -> {
// 4、获取spu的介绍 pms_spu_info_desc
SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(res.getSpuId());
skuItemVo.setDesp(spuInfoDescEntity);
}, executor);

CompletableFuture baseAttrFuture = infoFuture.thenAcceptAsync((res) -> {
// 5、获取spu的规格参数信息
List attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getCatalogId(), res.getSpuId());
skuItemVo.setAttrGroups(attrGroupVos);
}, executor);

CompletableFuture imageFuture = CompletableFuture.runAsync(() -> {
// 2、获取sku的图片信息 pms_spu_images
List skuImagesEntities = skuImagesService.getImageBySkuId(skuId);
skuItemVo.setImages(skuImagesEntities);
}, executor);

// 6、查询当前sku是否参与秒杀优惠
CompletableFuture secKillFuture = CompletableFuture.runAsync(() -> {
R skuSecKillInfo = secKillFeignService.getSkuSecKillInfo(skuId);
if (skuSecKillInfo.getCode() == 0) {
SecKillInfoVo skuSecKillInfoData = skuSecKillInfo.getData(new TypeReference() {
});
skuItemVo.setSecKillInfoVo(skuSecKillInfoData);
}
}, executor);

// 等到所有任务都完成
CompletableFuture.allOf(saleFuture, descFuture, baseAttrFuture, imageFuture, secKillFuture).get();

return skuItemVo;
}

posted @ 2021-06-09 01:04  jock_javaEE  阅读(79)  评论(0)    收藏  举报