CompletableFuture是什么
- 简单的任务,用Future获取结果还好,但我们并行提交的多个异步任务,往往并不是独立的,很多时候业务逻辑处理存在串行[依赖]、并行、聚合的关系。
- CompletableFuture是Future接口的扩展和增强。
- CompletableFuture实现了对任务的编排能力。
- 虽然通过CountDownLatch等工具类也可以实现任务的编排,但需要复杂的逻辑处理,不仅耗费精力且难以维护。
CompletableFuture的主要功能介绍
- thenApply:把前面异步任务的结果,交给后面的Function
- thenCompose:用来连接两个有依赖关系的任务,结果由第二个任务返回
- thenCombine:任务合并,有返回值
- thenAccepetBoth:两个任务执行完成后,将结果交给thenAccepetBoth消耗,无返回值。
- runAfterBoth:两个任务都执行完成后,执行下一步操作(Runnable)。
- applyToEither:两个任务谁执行的快,就使用那一个结果,有返回值。
- acceptEither: 两个任务谁执行的快,就消耗那一个结果,无返回值。
- runAfterEither: 任意一个任务执行完成,进行下一步操作(Runnable)。
- CompletableFuture类自己也提供了anyOf()和allOf()用于支持多个CompletableFuture并行执行
- join:无异常抛出
- get:抛出的是经过检查的异常,ExecutionException, InterruptedException
- whenComplete:正常的结果处理
- exceptionally:异常的结果处理
- whenCompleteAsync:正常的结果处理,开启新线程
- thenApply:使用一阶段的结果用在二阶段,返回一个具有处理结果的Future对象。
- thenCompose:使用一阶段的结果用在二阶段,返回 CompletableFuture 实例的函数,该函数的参数是先前计算步骤的结果。
- thenAccept系列:对单个结果进行消费
- thenAcceptBoth系列:对两个结果进行消费
- thenRun系列:不关心结果,只对结果执行Action
- thenCombine:合并两个线程任务的结果,并进一步处理。
- applyToEither:两个线程任务相比较,先获得执行结果的,就对该结果进行下一步的转化操作。返回CompletionStage<U>。
- acceptEither:两个线程任务相比较,先获得执行结果的,就对该结果进行下一步的消费操作。返回CompletionStage<Void>。
- runAfterEither:两个线程任务相比较,有任何一个执行完成,就进行下一步操作,不关心运行结果。返回CompletionStage<Void>。
- runAfterBoth:两个线程任务相比较,两个全部执行完成,才进行下一步操作,不关心运行结果。返回CompletionStage<Void>。
- anyOf:方法的参数是多个给定的 CompletableFuture,当其中的任何一个完成时,方法返回这个 CompletableFuture。
- allOf:方法用来实现多 CompletableFuture 的同时返回。
CompletableFuture的使用方式
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 执行无返回结果的异步任务
CompletableFuture.runAsync(() -> System.out.println("执行无返回结果的异步任务"));
// 执行有返回值的异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("执行有返回值的异步任务");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello World";
});
// 打印有返回值异步任务的返回值
System.out.println(future.get());
}
}
CompletableFuture的创建异步操作源码分析
/**
* Supplier函数式接口类型为参数,有返回值,会阻塞
*/
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(asyncPool, supplier);
}
/**
* Supplier函数式接口类型和具体使用的线程池为参数,有返回值,会阻塞
*/
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
Executor executor) {
return asyncSupplyStage(screenExecutor(executor), supplier);
}
/**
* 传入一个具体任务,执行的时候没有返回值!
*/
public static CompletableFuture<Void> runAsync(Runnable runnable) {
return asyncRunStage(asyncPool, runnable);
}
/**
* 传入一个具体任务和使用的线程池,执行的时候没有返回值
*/
public static CompletableFuture<Void> runAsync(Runnable runnable,
Executor executor) {
return asyncRunStage(screenExecutor(executor), runnable);
}
/**
* 我们一般是多核处理器,如果不传入具体的线程池,则使用ForkJoinPool做为默认的线程池。
*/
private static final Executor asyncPool = useCommonPool ?
ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
/**
* 有返回值的具体创建方式
*/
static <U> CompletableFuture<U> asyncSupplyStage(Executor e,
Supplier<U> f) {
// 传入的任务为null,抛异常
if (f == null) throw new NullPointerException();
// 创建一个CompletableFuture对象
CompletableFuture<U> d = new CompletableFuture<U>();
// 执行具体的任务:并通过CAS的方式设置结果
e.execute(new AsyncSupply<U>(d, f));
// 返回具体的结果
return d;
}
/**
* 无返回值的具体创建方式
*/
static CompletableFuture<Void> asyncRunStage(Executor e, Runnable f) {
// 传入的任务weinull,抛异常
if (f == null) throw new NullPointerException();
// 创建一个CompletableFuture对象
CompletableFuture<Void> d = new CompletableFuture<Void>();
// 执行具体的任务:无任何设置结果的代码
e.execute(new AsyncRun(d, f));
// 返回具体的结果
return d;
}
CompletableFuture的获取返回结果的方法join&get源码分析
/**
* 获取结果的方法,不抛出异常
*/
public T join() {
Object r;
return reportJoin((r = result) == null ? waitingGet(false) : r);
}
/**
* 抛出异常
*/
public T get() throws InterruptedException, ExecutionException {
Object r;
return reportGet((r = result) == null ? waitingGet(true) : r);
}
/**
* join的获取方法
*/
private static <T> T reportJoin(Object r) {
// 判断有没有异常,对各种异常进行判断并抛出
if (r instanceof AltResult) {
Throwable x;
if ((x = ((AltResult)r).ex) == null)
return null;
if (x instanceof CancellationException)
throw (CancellationException)x;
if (x instanceof CompletionException)
throw (CompletionException)x;
throw new CompletionException(x);
}
// 强转并返回结果
@SuppressWarnings("unchecked") T t = (T) r;
return t;
}
/**
* get的获取方法
*/
private static <T> T reportGet(Object r)
throws InterruptedException, ExecutionException {
// 结果不存在,抛异常
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;
}
/**
* 等待获取最后的结果
*/
private Object waitingGet(boolean interruptible) {
// Completion的子类,用于记录阻塞
Signaller q = null;
// 阻塞记录是否已放入任务栈中
boolean queued = false;
// 自旋的标志,-1代表未启动自旋,0代表已结束自旋,>0代表自旋进行中
int spins = -1;
// 具体返回的结果
Object r;
// 还没有结果的时候进入循环
while ((r = result) == null) {
// 自旋的标志小于0,说明未启动
if (spins < 0)
// private static final int SPINS = (Runtime.getRuntime().availableProcessors() > 1 ? 1 << 8 : 0);
// 多核CPU这里的值是256,单核CPU的值为0
spins = SPINS;
// 自旋的标志大于0,说明正在自旋
else if (spins > 0) {
// 取一个随机数,看看要不要进行处理自旋次数
if (ThreadLocalRandom.nextSecondarySeed() >= 0)
--spins;
}
// 判断到这里,说明spins为0,准备进行阻塞
// 阻塞队列中无内容的时候,进行创建队列
else if (q == null)
// 创建新的阻塞
q = new Signaller(interruptible, 0L, 0L);
// 不是第一次入队
else if (!queued)
// 入队操作
queued = tryPushStack(q);
// 判断当前的节点是否被中断
else if (interruptible && q.interruptControl < 0) {
// 取消线程的绑定
q.thread = null;
// 清楚队列中的当前节点
cleanStack();
// 返回结果为null
return null;
}
// 还没有获取到结果
else if (q.thread != null && result == null) {
try {
// 阻塞
ForkJoinPool.managedBlock(q);
} catch (InterruptedException ie) {
// 阻塞中途出现问题,修改变量
q.interruptControl = -1;
}
}
}
// 执行到这里说明获取到了值
if (q != null) {
// 释放线程
q.thread = null;
// 中断后的判断
if (q.interruptControl < 0) {
if (interruptible)
r = null; // report interruption
else
Thread.currentThread().interrupt();
}
}
// 将后续执行的任务唤醒。
postComplete();
// 返回具体的结果
return r;
}
CompletableFuture的结果处理方法使用
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.BiConsumer;
import java.util.function.Function;
public class CompletableFutureTest2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (new Random().nextInt(10) % 2 == 0) {
System.out.println("出现异常!");
int i = 12 / 0;
}
System.out.println("执行结束!");
return "test";
});
future.whenComplete(new BiConsumer<String, Throwable>() {
@Override
public void accept(String t, Throwable action) {
System.out.println(t + " 执行完成!");
}
});
future.exceptionally(new Function<Throwable, String>() {
@Override
public String apply(Throwable t) {
System.out.println("执行失败:" + t.getMessage());
return "异常xxxx";
}
});
}
}
结束语
- 获取更多本文的前置知识文章,以及新的有价值的文章,让我们一起成为架构师!
- 关注公众号,可以让你对MySQL、并发编程、spring源码有深入的了解!
- 关注公众号,后续持续高效的学习JVM!
- 这个公众号,无广告!!!每日更新!!!