1.文章目录
- ComPletableFuture概述
- CompletableFuture实践
- CompletableFuture主要源码导读
2.CompletableFuture概述
- CompleatableFuture是对Future的增强,我们知道Future的局限性,CompleatableFuture可以通过编程方式显式设置计算结果和状态,并且可以作为一个计算阶段,当他完成时还能触发另一个函数/行为;
- 当多个线程调用CompletableFuture的complete,cancel方式只有一个线程会成功;
- CompletableFuture实现了CompletionStage接口方法:主要是当CompletableFuture任务结束后,同步使用任务来执行依赖任务结果的函数/行为
- 所有异步的方法在没有执行Executor参数情况下,都是用ForkJoinPool.commonPool线程池来执行;
- 所有实现CompletionStage的方法都是相互独立的实现,不会因为重载其他方法影响;
- 另外:CompletableFuture的结果有一些任务依赖于此,利用的无锁栈结构(CAS实现),因此执行顺序和依赖顺序相反;
3.CompletableFuture实践
显式设置CompletableFuture结果
public class CompletableFutureTest {
// 自定义线程池
private final static int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private final static ThreadPoolExecutor POOL_EXECUTOR = new ThreadPoolExecutor(CPU_COUNT, 2 * CPU_COUNT, 1,
TimeUnit.MINUTES, new LinkedBlockingQueue<>(5), new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] argv) throws ExecutionException, InterruptedException {
CompletableFuture<String> completableFuture = new CompletableFuture<String>();
POOL_EXECUTOR.execute(()->{
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 设置future结果
System.out.println("---" + Thread.currentThread().getName() + " set future result --- ");
completableFuture.complete("niuBi");
// 等待异步执行结果
System.out.println("main wait future result");
System.out.println(completableFuture.get());
System.out.println("main get future result");
// 关闭线程池
POOL_EXECUTOR.shutdown();
}
}
- 创建线程池,提交任务到异步线程池,主线程调用get等待线程执行完任务,会阻塞主线程;
基于CompletableFuture实现异步计算与结果转化
- 基于runAsync系列方法实现无返回值的异步计算;
- 异步打印日志,Dubbo异步存放配置信息,异步消息通知等模型
public class CompletableFutureTest {
public static void runAsync() throws ExecutionException, InterruptedException {
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("over");
}
});
System.out.println(completableFuture.get());
}
public static void main(String[] argv) throws ExecutionException, InterruptedException {
runAsync();
}
}
- future.get获取的是null,我们知道默认是ForkJoinPool.commonPool线程池,我们也可以自己实现线程池;
public class CompletableFutureTest {
// 自定义线程池
private final static int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private final static ThreadPoolExecutor POOL_EXECUTOR = new ThreadPoolExecutor(CPU_COUNT, 2 * CPU_COUNT, 1,
TimeUnit.MINUTES, new LinkedBlockingQueue<>(5), new ThreadPoolExecutor.AbortPolicy());
public static void runAsync() throws ExecutionException, InterruptedException {
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("over");
}
}, POOL_EXECUTOR);
System.out.println(completableFuture.get());
}
public static void main(String[] argv) throws ExecutionException, InterruptedException {
runAsync();
}
}
- 基于supplyAsync系列方法实现有返回值的异步计算
- future.get返回"niuBi",也可以转化为自定义线程池执行异步任务
public static void supplyAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 返回异步计算
return "niuBi";
}
});
System.out.println(completableFuture.get());
}
自定义线程池:完成有返回值异步计算
public class CompletableFutureTest {
// 自定义线程池
private final static int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private final static ThreadPoolExecutor POOL_EXECUTOR = new ThreadPoolExecutor(CPU_COUNT, 2 * CPU_COUNT, 1,
TimeUnit.MINUTES, new LinkedBlockingQueue<>(5), new ThreadPoolExecutor.AbortPolicy());
public static void supplyAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 返回异步计算
return "niuBi";
}
}, POOL_EXECUTOR);
System.out.println(completableFuture.get());
}
public static void main(String[] argv) throws ExecutionException, InterruptedException {
supplyAsync();
POOL_EXECUTOR.shutdown();
}
}
- 基于thenRun实现异步任务A,执行完毕后,激活任务B,这种方式激活的异步任务B拿不到任务A的执行结果;
public static void thenRun() throws ExecutionException, InterruptedException {
CompletableFuture<String> oneFuture = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one future end");
// 返回异步结果
return "hello, NiuBi";
}
});
CompletableFuture<Void> twoFuture = oneFuture.thenRun(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("two Future end");
});
// 同步等待twoFuture结束
System.out.println(twoFuture.get());
}
- 基于thenAccept实现异步任务A,执行完后,激活任务B,B获取A的结果搞事情;
- future.get的结果为null;
public static void thenAccept() throws ExecutionException, InterruptedException {
CompletableFuture<String> oneFuture = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one future end");
return "niuBi";
}
});
CompletableFuture<Void> twoFuture = oneFuture.thenAccept(new Consumer<String>() {
@Override
public void accept(String result) {
// 对oneFuture的结果操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("two future get one future result : " + result + " add ");
}
});
System.out.println(twoFuture.get());
}
- 基于thenApply实现任务A,完成后,激活任务B执行,B可以拿到A的结果,并且我们可以获得B的结果
- 默认的oneFuture以及回调事件twoFuture在ForkJoin线程池是同一线程,如果用自定义线程池,调度的线程可能不一样;
public static void thenApply() throws ExecutionException, InterruptedException {
CompletableFuture<String> oneFuture = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one future end");
return "niuBi";
}
});
CompletableFuture<String> twoFuture = oneFuture.thenApply(
// arg1:前任务的返回结果类型,arg2:回调函数的返回类型
new Function<String, String>() {
@Override
public String apply(String preResult) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return preResult + " two future add";
}
});
System.out.println(twoFuture.get());
}
- 基于whenComplete设置回调函数:当异步任务执行完毕后进行回调,不会阻塞调用线程;
public class CompletableFutureTestDubbo {
private static final CountDownLatch countDownLatch = new CountDownLatch(1);
public static void main(String[] argv) throws InterruptedException {
CompletableFuture<String> oneFuture = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
return "niuBi";
}
});
oneFuture.whenComplete(new BiConsumer<String, Throwable>() {
@Override
public void accept(String s, Throwable throwable) {
// 如果没有异常
if (null == throwable){
System.out.println(s);
} else {
throwable.printStackTrace();
}
}
});
countDownLatch.await();
}
}
- 多个CompletableFuture进行组合运算
- 基于thenCompose实现当一个CompletableFuture执行完毕,执行另一个CompletableFuture
public class CompletableFutureTestDubbo {
private static final CountDownLatch countDownLatch = new CountDownLatch(1);
public static CompletableFuture<String> doSomethingOne(String encodedCompanyId){
return CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return encodedCompanyId;
}
});
}
public static CompletableFuture<String> doSomethingTwo(String companyId){
return CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return companyId + "阿里云";
}
});
}
public static void main(String[] argv) throws InterruptedException, ExecutionException {
CompletableFuture<String> completableFuture = doSomethingOne("123").thenCompose(id -> doSomethingTwo(id));
System.out.println(completableFuture.get());
}
}
- 基于thenCombine实现:两个并发任务结束,使用两者的结果作为参数;
public class CompletableFutureTestDubbo {
private static final CountDownLatch countDownLatch = new CountDownLatch(1);
public static CompletableFuture<String> doSomethingOne(String encodedCompanyId){
return CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return encodedCompanyId;
}
});
}
public static CompletableFuture<String> doSomethingTwo(String companyId){
return CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return companyId + "阿里云";
}
});
}
public static void main(String[] argv) throws InterruptedException, ExecutionException {
CompletableFuture<Object> completableFuture = doSomethingOne("123").thenCombine(doSomethingTwo("456"), (oneResult, twoResult) -> {
return oneResult + ":" + twoResult;
});
System.out.println(completableFuture.get());
}
}
- 基于AllOf等待所有并发任务结束
public class CompletableFutureTestDubbo {
private static final CountDownLatch countDownLatch = new CountDownLatch(1);
public static CompletableFuture<String> doSomethingOne(String encodedCompanyId){
return CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("do SomethingOne");
return encodedCompanyId;
}
});
}
public static CompletableFuture<String> doSomethingTwo(String companyId){
return CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("do SomethingTwo");
return companyId + "阿里云";
}
});
}
public static void main(String[] argv) throws InterruptedException, ExecutionException {
List<CompletableFuture<String>> futureList = new ArrayList<>();
futureList.add(doSomethingOne("111"));
futureList.add(doSomethingOne("222"));
futureList.add(doSomethingOne("333"));
futureList.add(doSomethingTwo("444"));
futureList.add(doSomethingTwo("555"));
CompletableFuture<Void> completableFuture = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));
System.out.println(completableFuture.get());
}
}
- 基于anyof实现当任务集合中一个任务结束就会返回,但是任务都会运行完;
public class CompletableFutureTestDubbo {
private static final CountDownLatch countDownLatch = new CountDownLatch(1);
public static CompletableFuture<String> doSomethingOne(String encodedCompanyId){
return CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("do SomethingOne");
return encodedCompanyId;
}
});
}
public static CompletableFuture<String> doSomethingTwo(String companyId){
return CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("do SomethingTwo");
return companyId + "阿里云";
}
});
}
public static void main(String[] argv) throws InterruptedException, ExecutionException {
List<CompletableFuture<String>> futureList = new ArrayList<>();
futureList.add(doSomethingOne("111"));
futureList.add(doSomethingOne("222"));
futureList.add(doSomethingOne("333"));
futureList.add(doSomethingTwo("444"));
futureList.add(doSomethingTwo("555"));
CompletableFuture<Object> completableFuture = CompletableFuture.anyOf(futureList.toArray(new CompletableFuture[futureList.size()]));
System.out.println(completableFuture.get());
}
异常处理
- 当任务的处理过程出现异常,如何处理;
- 如下代码,我们抛出异常,导致future.get一直阻塞,线上操作是致命的;
public class CompletableFutureExpectionTest {
public static void main(String[] argv) throws ExecutionException, InterruptedException {
CompletableFuture<String> completableFuture = new CompletableFuture<>();
new Thread(()->{
try {
if (true){
throw new RuntimeException("error cause");
}
completableFuture.complete("success");
}catch (Exception e) {
}
System.out.println(Thread.currentThread().getName() + " set result");
}, "threadA").start();
System.out.println(completableFuture.get());
}
}
- completeExceptionAlly方法处理异常情况:如下代码,会打印异常信息
public class CompletableFutureExpectionTest {
public static void main(String[] argv) throws ExecutionException, InterruptedException {
CompletableFuture<String> completableFuture = new CompletableFuture<>();
new Thread(()->{
try {
if (true){
throw new RuntimeException("error cause");
}
completableFuture.complete("success");
}catch (Exception e) {
completableFuture.completeExceptionally(e);
}
System.out.println(Thread.currentThread().getName() + " set result");
}, "threadA").start();
//System.out.println(completableFuture.exceptionally(t-> "defalut").get());
System.out.println(completableFuture.get());
}
}
- 以上是对于CompletableFuture的实践,具体业务可以更加灵活的扩展,结合应用;
4.CompletableFuture源码导读
基本属性:保存变量偏移量,CAS操作修改;
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long RESULT;
private static final long STACK;
private static final long NEXT;
static {
try {
final sun.misc.Unsafe u;
UNSAFE = u = sun.misc.Unsafe.getUnsafe();
Class<?> k = CompletableFuture.class;
RESULT = u.objectFieldOffset(k.getDeclaredField("result"));
STACK = u.objectFieldOffset(k.getDeclaredField("stack"));
NEXT = u.objectFieldOffset
(Completion.class.getDeclaredField("next"));
} catch (Exception x) {
throw new Error(x);
}
}
reportget
private static <T> T reportGet(Object r)
throws InterruptedException, ExecutionException {
// 如果r为null则抛出异常
if (r == null) // by convention below, null means interrupted
throw new InterruptedException();
// 如果是异常类
if (r instanceof AltResult) {
Throwable x, cause;
// 根据异常类型,抛出异常
if ((x = ((AltResult)r).ex) == null)
return null;
if (x instanceof CancellationException)
throw (CancellationException)x;
if ((x instanceof CompletionException) &&
(cause = x.getCause()) != null)
x = cause;
throw new ExecutionException(x);
}
// 转化结果
@SuppressWarnings("unchecked") T t = (T) r;
return t;
}
线程池,Task运行本质
// 默认为forkjoinPool
private static final Executor asyncPool = useCommonPool ?
ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
// Task本质,创建线程运行
static final class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) { new Thread(r).start(); }
}
Completion代表一个异步计算节点
abstract static class Completion extends ForkJoinTask<Void>
implements Runnable, AsynchronousCompletionTask {
// 节点链
volatile Completion next; // Treiber stack link
abstract CompletableFuture<?> tryFire(int mode);
/** Returns true if possibly still triggerable. Used by cleanStack. */
abstract boolean isLive();
//task的运行,其实就是方法中写的run任务
public final void run() { tryFire(ASYNC); }
public final boolean exec() { tryFire(ASYNC); return true; }
public final Void getRawResult() { return null; }
public final void setRawResult(Void v) {}
}
runAsync(Runnable runnable):
public static CompletableFuture<Void> runAsync(Runnable runnable) {
return asyncRunStage(asyncPool, runnable);
}
static CompletableFuture<Void> asyncRunStage(Executor e, Runnable f) {
// 判空校验
if (f == null) throw new NullPointerException();
// 创建返回对象
CompletableFuture<Void> d = new CompletableFuture<Void>();
// 线程池执行
e.execute(new AsyncRun(d, f));
//返回future
return d;
}
static final class AsyncRun extends ForkJoinTask<Void>
implements Runnable, AsynchronousCompletionTask {
CompletableFuture<Void> dep; Runnable fn;
AsyncRun(CompletableFuture<Void> dep, Runnable fn) {
this.dep = dep; this.fn = fn;
}
public final Void getRawResult() { return null; }
public final void setRawResult(Void v) {}
public final boolean exec() { run(); return true; }
public void run() {
CompletableFuture<Void> d; Runnable f;
if ((d = dep) != null && (f = fn) != null) {
dep = null; fn = null;
// 任务没有完成
if (d.result == null) {
try {
// 运行
f.run();
//设置返回结果null
d.completeNull();
} catch (Throwable ex) {
d.completeThrowable(ex);
}
}
//弹出依赖当前结果的节点,执行
d.postComplete();
}
}
}
CompletableFuture<U> supplyAsync(Supplier<U> supplier):有返回结果
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(asyncPool, supplier);
}
static <U> CompletableFuture<U> asyncSupplyStage(Executor e,
Supplier<U> f) {
if (f == null) throw new NullPointerException();
// 创建future对象
CompletableFuture<U> d = new CompletableFuture<U>();
// 线程池执行AsyncSupply对象(包装f)
e.execute(new AsyncSupply<U>(d, f));
// 返回future
return d;
}
public void run() {
CompletableFuture<T> d; Supplier<T> f;
if ((d = dep) != null && (f = fn) != null) {
dep = null; fn = null;
if (d.result == null) {
try {
// f.get获取值
d.completeValue(f.get());
} catch (Throwable ex) {
d.completeThrowable(ex);
}
}
// 通知依赖节点
d.postComplete();
}
- 介绍l主要的运行任务方法;
int getNumberOfDependents:获取依赖该节点的任务数
// 获取依赖该节点的任务数
public int getNumberOfDependents() {
int count = 0;
// 遍历一遍
for (Completion p = stack; p != null; p = p.next)
++count;
return count;
}
- 基本的方法实现已经结束;
4.总结
- CompletableFuture对异步编程的支持很强,可以根据我们的业务进行灵活的运用;在框架中异步思想的运行很多,因此对CompletableFuture的运用要非常熟悉,后续我们对CompletableFuture的所有方法细节实现进行导读,如何通知其他依赖节点,then系列方法执行后,是如何保存节点信息,异常情况,其他信息如何处理等;