开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
CompletableFuture的特性理解
以前使用多线程处理的时候,常用的就是实现Runnable接口或者callable接口,然后通过线程池submit()或者execute();如果是submit()可以用Future来进行接受
CompletableFuture我的理解就是集合封装了上述能力的集合;;
- Callable就是具有返回结果的动作任务
- Runable 就是没有无返回值的动作任务
- Future 里面封装了callable和runable的能力,然后交给线程池使用执行,如果需要结果就future.get()或者结果
- CompletableFuture即而封装了future,使其拥有了回调的功能,在某个行为动作完成之后,继续进行下一个动作。有点链式编程的意思;
话不多说上例子
public static void main(String[] args) throws InterruptedException {
long curr = System.currentTimeMillis();
ExecutorService executorService = Executors.newFixedThreadPool(10);
// List<String> list = new ArrayList();
List<String> list = Collections.synchronizedList(new ArrayList<String>());
int d = 10;
CountDownLatch countDownLatch = new CountDownLatch(11);
for (int i=0;i<=d;i++){
int finalI = i;
CompletableFuture.runAsync(() ->{
System.out.println(Thread.currentThread().getName() + "---时间"+System.currentTimeMillis());
list.add( PolicyTaskRepositoryImpl.addX(finalI));
countDownLatch.countDown();
},executorService);
}
countDownLatch.await();
long now = System.currentTimeMillis();
System.out.println("耗时:"+(now-curr)/1000+ "秒"+ JSON.toJSONString(list));
}
public static String addX(int x){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return x+"dds";
}
执行结果:
解析代码
代码中的逻辑就是for循环中重复调用某个耗时方法(可以类比为数据库),此时加上多线程并行查询,然后等待所有的子线程执行完成之后,再将结果聚合到list中返回
- Collections.synchronizedList(new ArrayList()) 为了防止结果插入到Arraylist中# 多线程高并发情况下ArrayList集合不安全问题
- CountDownLatch 可以理解为就是一个计数器,目的是确认所有的子线程都跑完了,再执行main线程
- CompletableFuture.runAsync() 异步执行 不需要返回值
- CompletableFuture.supplyAsync() 异步执行 ,需要返回值使用
总结
上述例子是业务场景中的一个简化单demo,效果是接口从22秒减少到了2秒以内,所以在某些使用的时候还是很有用的,但是异步执行有一个问题就是traceId日志链路不太好串起来,就看各个公司有没有分布式日志底层工具。。每日记录一点点🤏