我们都知道代码块的执行顺序,一般是从上至下执行;
如果有三个方法,从上至下执行的话需要花1.5s;
如果使用线程池异步执行的话,只需要0.5s,这将大大减少方法整体执行时间;
下面介绍,线程池的创建及使用。
1.创建线程池
有两种方法可以创建线程池,推荐使用第一种。
1.1创建原生的线程池对象(本人推荐使用这个)
package com.wanxin.gulimall.order.config;
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;
/**
* 我线配置
*
* @author common
* @date 2022/05/19
*/
@Configuration
public class MyThreadConfig {
@Bean
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) {
return new ThreadPoolExecutor(
//核心线程数量
20,
//最大线程数量
200,
//最大存活时间
10,
//单位秒
TimeUnit.SECONDS,
//队列,
new LinkedBlockingDeque<>(100000),
//线程工厂,构建线程
Executors.defaultThreadFactory(),
//任务具有策略
new ThreadPoolExecutor.AbortPolicy());
}
}
1.2 使用Executors的工具方法直接得到一个线程池对象
package d7_threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//使用Executors的工具方法直接得到一个线程池对象
public class ThreadPoolDemo3 {
public static void main(String[] args) {
//1.创建固定数量的线程池
ExecutorService pool= Executors.newFixedThreadPool(3);
}
}
2.操作线程池实现方法异步执行
2.1 runAsync ()方法 --- 无返回值
2.2 supplyAsync()方法 --- 有返回值
package com.wanxin.gulimall.search.thread;
import java.util.concurrent.*;
/**
* 线程测试
*
* @author 万天铭
* @date 2022/05/18
*/
public class thread {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*无返回值*/
CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
System.out.println("当前线程"+Thread.currentThread().getId());
int i=10/2;
System.out.println("运行结果"+i);
}, executor);
}
}
2.3 whenComplete() 方法 --- 方法完成后的感知
package com.wanxin.gulimall.search.thread;
import java.util.concurrent.*;
/**
* 线程测试
*
* @author 万天铭
* @date 2022/05/18
*/
public class thread {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*方法完成后的感知*/
CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果" + i);
return i;
}, executor).whenComplete((res,exception)->{
//虽然能得到异常信息,但是无法修改返回数据
System.out.println("异步任务完成。。。结果是:"+res+";异常是"+exception);
}).exceptionally(throwable -> {
//可以感知异常,同时返回默认值
return 10;
});
}
}
运行结果:
2.3 handle()方法 --- 方法完成后的处理
package com.wanxin.gulimall.search.thread;
import java.util.concurrent.*;
/**
* 线程测试
*
* @author 万天铭
* @date 2022/05/18
*/
public class thread {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*方法完成后的处理*/
CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果" + i);
return i;
}, executor).handle((res,thr)->{
if (res!=null){
System.out.println("处理结果" +res*2);
return res*2;
}
if (thr!=null){
return 0;
}
return 0;
});
}
}
运行结果:
3.线程串行化
3.1 thenRunAsync --- 不能获取上一步的执行结果,无返回值
3.2 thenAcceptAsync --- 能接收上一步的结果,但是无返回值
3.3 thenApplyAsync --- 能接收上一步的结果,而且有返回值
/*
* 线程串行化
* 1) thenRunAsync: 不能获取上一步的执行结果,无返回值
* .thenRunAsync(() -> {
System.out.println("任务2启动了");
}, executor);
*
* 2) thenAcceptAsync: 能接收上一步的结果,但是无返回值
* .thenAcceptAsync(res->{
System.out.println("任务2启动了"+res);
});
*
* 3)thenApplyAsync 能接收上一步的结果,而且有返回值
* */
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果" + i);
return i;
}, executor).thenApplyAsync(res -> {
System.out.println("任务2启动了" + res);
return "hello" + res;
}, executor);
System.out.println("任务2返回值"+future.get());
}
运行结果:
3.4 runAfterBothAsync 等待前两个任务执行完之后再执行此方法(无返回值)
3.5 thenAcceptBothAsync 等待前两个任务执行完之后再执行此方法(有返回值)
3.6 runAfterEitherAsync 两个任务,只要一个执行完成,就执行任务3 ( 不感知结果,自己业务返回值)
3.7 anyOf 必须所有任务执行完成,才算成功
3.8 allOf 只要一个执行完成,就算成功
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务线程1");
return "任务线程1";
}, executor);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务线程2");
return "任务线程2";
}, executor);
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务线程3");
return "任务线程3";
}, executor);
/* 等待前两个任务执行完之后再执行此方法(无返回值)*/
future1.runAfterBothAsync(future2,()->{
System.out.println("任务线程3开始");
}, executor);
/* 等待前两个任务执行完之后再执行此方法(有返回值)*/
// future1.thenAcceptBothAsync(future2,(f1,f2)->{
// System.out.println("任务线程3开始,之前的结果:"+f1+"---->>"+f2);
// },executor);
/*
* 两个任务,只要一个执行完成,就执行任务3
* runAfterEitherAsync 不感知结果,自己业务返回值
* */
// future1.runAfterEitherAsync(future2,()->{
// System.out.println("任务线程3开始");
// },executor);
// /*必须所有任务执行完成,才算成功*/
// CompletableFuture<Object> allOf = CompletableFuture.allOf(future1, future2, future3);
// anyOf.get();
//
//
// /*只要一个执行完成,就算成功*/
// CompletableFuture<Void> anyOf = CompletableFuture.anyOf(future1, future2, future3);
// future.get();
4.项目线程池异步执行案例
4.1 application.properties配置文件中定义变量
gulimall.thread.coreSize=20
gulimall.thread.maxSize=200
gulimall.thread.keepAliveTime=10
4.2 定义类接收变量
package com.atguigu.gulimall.product.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 线程池配置属性
*
* @author common
* @date 2022/05/19
*/
@ConfigurationProperties(prefix = "gulimall.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
private Integer coreSize;
private Integer maxSize;
private Integer keepAliveTime;
}
4.3 线程池属性配置
package com.atguigu.gulimall.product.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.*;
/**
* 我线配置
*
* @author common
* @date 2022/05/19
*/
@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());
}
}
4.4 使用线程池
@Autowired
ThreadPoolExecutor threadPoolExecutor;
@Override
public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
//1、sku基本信息的获取 pms_sku_info
SkuItemVo skuItemVo=new SkuItemVo();
CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
SkuInfoEntity info = getById(skuId);
skuItemVo.setInfo(info);
return info;
}, threadPoolExecutor);
//==============================下面三个异步==================================//
CompletableFuture<Void> attrFuture = infoFuture.thenAcceptAsync(res -> {
//3、获取spu的销售属性组合
List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrBySpuId(res.getSpuId());
skuItemVo.setSaleAttr(saleAttrVos);
}, threadPoolExecutor);
CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync(res -> {
//4、获取spu的介绍
SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(res.getSpuId());
skuItemVo.setDesc(spuInfoDescEntity);
}, threadPoolExecutor);
CompletableFuture<Void> baseAttrFuture = infoFuture.thenAcceptAsync(res -> {
//5、获取spu的规格参数信息
List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
skuItemVo.setGroupAttrs(attrGroupVos);
}, threadPoolExecutor);
//================================================================//
CompletableFuture<Void> imagesFuture= CompletableFuture.runAsync(() -> {
//2、sku的图片信息 pms_sku_images
List<SkuImagesEntity> imagesEntities = skuImagesService.getImagesBySkuId(skuId);
skuItemVo.setImages(imagesEntities);
}, threadPoolExecutor);
//等待所有任务都完成
CompletableFuture.allOf(attrFuture,descFuture,baseAttrFuture,imagesFuture).get();
return skuItemVo;
}