官方文档:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html
1 示例
Demo1:验证CompletableFuture的阻塞和异步
public class CompletableFutureTest {public static void main(String[] args) {Long start = System.currentTimeMillis();// new CompletableFutureTest().futureBlock();Long end = System.currentTimeMillis();// System.out.println("futhre阻塞耗时:" + (end - start));Long start2 = System.currentTimeMillis();new CompletableFutureTest().futhreSync();Long end2 = System.currentTimeMillis();System.out.println("futhre异步耗时:" + (end2 - start2));}public void futureBlock() {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(10000),new ThreadFactoryBuilder().setNameFormat("checkExcelImportProductInfoList-pool-%d").build(),new ThreadPoolExecutor.CallerRunsPolicy());List<CompletableFuture> list = new ArrayList();for (int i = 0; i < 10; i++) {int finalI = i;CompletableFuture future = CompletableFuture.supplyAsync(() -> this.toDo(finalI), threadPoolExecutor).exceptionally(e -> {e.printStackTrace();return null;});list.add(future);}list.stream().forEach(m -> {try {Map map = (Map) m.get();//阻塞next(map);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}});threadPoolExecutor.shutdown();}public void futhreSync() {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(10000),new ThreadFactoryBuilder().setNameFormat("checkExcelImportProductInfoList-pool-%d").build(),new ThreadPoolExecutor.CallerRunsPolicy());for (int i = 0; i < 10; i++) {int finalI = i;CompletableFuture future = CompletableFuture.supplyAsync(() -> this.toDo(finalI), threadPoolExecutor).thenApply(map -> {next(map);return null;}).exceptionally(e -> {e.printStackTrace();return null;});}threadPoolExecutor.shutdown();}public Map toDo(int i) {if (i == 3 ) {try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}}if (i == 6 ) {try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}Map map = new HashMap();map.put(i, Thread.currentThread().getName());return map;}public void next(Map map) {Iterator i = map.keySet().iterator();while (i.hasNext()) {Integer integer = (Integer) i.next();System.out.println("key:" + integer + " ;value:" + map.get(integer));}}}
运行阻塞方法futureBlock时,输出:
key:0 ;value:checkExcelImportProductInfoList-pool-0key:1 ;value:checkExcelImportProductInfoList-pool-1key:2 ;value:checkExcelImportProductInfoList-pool-2key:3 ;value:checkExcelImportProductInfoList-pool-3key:4 ;value:checkExcelImportProductInfoList-pool-4key:5 ;value:checkExcelImportProductInfoList-pool-0key:6 ;value:checkExcelImportProductInfoList-pool-0key:7 ;value:checkExcelImportProductInfoList-pool-1key:8 ;value:checkExcelImportProductInfoList-pool-1key:9 ;value:checkExcelImportProductInfoList-pool-1futhre阻塞耗时:10082
在i=3时阻塞10s,导致其他线程无法进行下一步
运行异步futhreSync方法时,输出:
key:0 ;value:checkExcelImportProductInfoList-pool-0key:1 ;value:checkExcelImportProductInfoList-pool-1futhre异步耗时:80key:5 ;value:checkExcelImportProductInfoList-pool-0key:7 ;value:checkExcelImportProductInfoList-pool-0key:8 ;value:checkExcelImportProductInfoList-pool-0key:9 ;value:checkExcelImportProductInfoList-pool-0key:2 ;value:checkExcelImportProductInfoList-pool-2key:4 ;value:checkExcelImportProductInfoList-pool-4key:6 ;value:checkExcelImportProductInfoList-pool-1key:3 ;value:checkExcelImportProductInfoList-pool-3
Demo2:验证CompletableFuture异步执行,并统计所有线程执行的结果
package com.tools.threadDemo.CompletableFutureTest;import com.google.common.util.concurrent.ThreadFactoryBuilder;import java.util.*;import java.util.concurrent.*;public class CompletableFutureTest2 {private ExecutorService threadPoolExecutor;public static void main(String[] args) {List<CompletableFuture> list = new ArrayList<>();List<Map> resultList = new ArrayList<>();//模拟统计所有线程的结果for (int i = 0; i < 10; i++) {list.add(new CompletableFutureTest2().futhreSync(i, resultList));}CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()])).join();//待所有线程执行完成后再执行System.out.println("result>>>>>>>>>>>>" + resultList);}private synchronized void initClientInfoExecutor(int corePoolSize, int maximumPoolSize) {threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(10000),new ThreadFactoryBuilder().setNameFormat("initClientInfoExecutor-pool-%d").build(),new ThreadPoolExecutor.CallerRunsPolicy());}public CompletableFuture futhreSync(int i, List<Map> mapList) {initClientInfoExecutor(8, 10);List<CompletableFuture> futureList = new ArrayList<>();int finalI = i;CompletableFuture future = CompletableFuture.supplyAsync(() -> this.toDo(finalI, mapList), threadPoolExecutor).thenApply(map -> {next(map);return map;}).exceptionally(e -> {e.printStackTrace();return null;});threadPoolExecutor.shutdown();return future;}/*** 多线程执行的任务*/public Map toDo(int i, List<Map> mapList) {if (i == 3) {try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}}if (i == 6) {try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}Map map = new HashMap();map.put(i, Thread.currentThread().getName());if (i % 2 == 0) {Map map1 = new HashMap();map1.put(i, Thread.currentThread().getName());mapList.add(map1);}return map;}/*** 必须依赖上一个线程执行完成后再执行*/public void next(Map map) {Iterator i = map.keySet().iterator();while (i.hasNext()) {Integer integer = (Integer) i.next();System.out.println("key:" + integer + " ;value:" + map.get(integer));}}}
输出:
key:0 ;value:initClientInfoExecutor-pool-0key:1 ;value:initClientInfoExecutor-pool-0key:2 ;value:initClientInfoExecutor-pool-0key:4 ;value:initClientInfoExecutor-pool-0key:5 ;value:initClientInfoExecutor-pool-0key:7 ;value:initClientInfoExecutor-pool-0key:8 ;value:initClientInfoExecutor-pool-0key:9 ;value:initClientInfoExecutor-pool-0key:6 ;value:initClientInfoExecutor-pool-0key:3 ;value:initClientInfoExecutor-pool-0result>>>>>>>>>>>>[{0=initClientInfoExecutor-pool-0}, {2=initClientInfoExecutor-pool-0}, {4=initClientInfoExecutor-pool-0}, {8=initClientInfoExecutor-pool-0}, {6=initClientInfoExecutor-pool-0}]
2 源码分析
2.1 andTree
andTree是allOf方法的底层实现,addTree的多个任务是各自独立并行执行,addTree将多个任务通过递归的方式两两组队,任一一个任务执行完成都会判断两两组队的两个任务是否都执行完了,如果是则触发上层的任务判断逻辑,直到最终所有任务都执行完了。
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {return andTree(cfs, 0, cfs.length - 1);}
//lo是起始数组索引,hi是终止数组索引static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs,int lo, int hi) {CompletableFuture<Void> d = new CompletableFuture<Void>();if (lo > hi) // 空d.result = NIL;else {CompletableFuture<?> a, b;int mid = (lo + hi) >>> 1;//通过递归,将多个任务转换成两两成对的,最底层的执行完了会触发上层//这里的触发只是任务是否执行完成的判断逻辑,各任务是各自独立并行执行if ((a = (lo == mid ? cfs[lo] :andTree(cfs, lo, mid))) == null ||(b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :andTree(cfs, mid+1, hi))) == null)throw new NullPointerException();//如果a,b有一个未执行完,则返回falseif (!d.biRelay(a, b)) {//不满足完成条件,生成一个中继并压栈,再次尝试同步完成。若不满足条件,ab任何一个完成后都会再间接调用它的tryFire。BiRelay<?,?> c = new BiRelay<>(d, a, b);//除非ab均完成,否则bipush要进ab两者的栈。a.bipush(b, c);c.tryFire(SYNC);}}return d;}
