1. CompletableFuture的介绍

在Java8时被引入,在包java.util.concurrent下,是Java多线程编程中的一个类,扩展了Future中很多功能,CompletableFuture是一个实现了接口Future和CompletionStage的类。

public class CompletableFuture<T> implements Future<T>, CompletionStage<T>

2. Future与CompletableFuture对比

1 Future#get阻塞方法,影响后续代码执行,CompletableFuture可以设置callback的方式处理:CompletableFuture#thenAcceptAsync
2 CompletableFuture可以组合多个CompletableFuture:CompletableFuture#thenCompose、anyof
3 CompletableFuture优雅处理线程异常:CompletableFuture#handle、exceptionally
4 CompletableFuture可以手动设置为完成,即一个线程处理任务的时间过长,可以手动设置为完成,并设置返回值:CompletableFuture#complete

3. CompletableFuture常用方法

3.1. CompletableFuture#runAsync

/**
* @see CompletableFuture#runAsync(Runnable) 接收一个Runnable参数
*/
@Test
public void runAsyncTest() {
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
System.out.println(getCurrentThreadName() + "------runSync method");
});
// ForkJoinPool.commonPool-worker-9------runSync method
}

  

3.2. CompletableFuture#supplyAsync

/**

     * @throws ExecutionException

     * @throws InterruptedException

     * @see CompletableFuture#supplyAsync(Supplier) 接受一个Supplier参数

     */

    @Test

    public void supplyAsyncTest() throws ExecutionException, InterruptedException {

        CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> "return a string of supplyAsync method");

        System.out.println(stringCompletableFuture.get());

        // return a string of supplyAsync method

    }

3.3. CompletableFuture#thenAccept

/**

     * @see CompletableFuture#thenAccept(Consumer) runAync或者supplyAsync执行完后进行的操作(callback)

     */

    @Test

    public void thenAcceptTest() {

        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {

            System.out.println(getCurrentThreadName() + "------runSync method");

        }).thenAccept((consumer) -> {

            System.out.println(getCurrentThreadName() + "------thenAccept method");

        });

        System.out.println(getCurrentThreadName() + " End");

        // ForkJoinPool.commonPool-worker-9------runSync method

        // main------thenAccept method

        // main End

    }

3.4. CompletableFuture#thenAcceptAsync

/**

     * @see CompletableFuture#thenAcceptAsync(Consumer)  异步callback

     */

    @Test

    public void thenAcceptAsyncTest() throws InterruptedException {

        AtomicReference<Thread> threadAtomicReference = new AtomicReference<>();

        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {

            threadAtomicReference.set(Thread.currentThread());

            System.out.println(getCurrentThreadName() + "------runSync method");

        }).thenAcceptAsync((consumer) -> {

            System.out.println(getCurrentThreadName() + "------thenAccept method");

            getCurrentThread().notifyAll();

        });

        TimeUnit.SECONDS.sleep(1);

        System.out.println(getCurrentThreadName() + " End");

//        ForkJoinPool.commonPool-worker-9------runSync method

//        ForkJoinPool.commonPool-worker-9------thenAccept method

//        main End

    }

3.5. CompletableFuture#thenApply

/**

     * @see CompletableFuture#thenApply(Function)

     */

    @Test

    public void thenApply() {

        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> "supplyAsync method")

                .thenApply((s) -> s + " -> theApply method")

                .thenAccept(System.out::println);

        // supplyAsync method -> theApply method

    }

3.6. CompletableFuture#thenCompose

/**
* @see CompletableFuture#thenCompose(Function) 作为两个CompletableFuture组合使用 这里的Function<? super T, ?
* extends CompletionStage<U>> T要转换成CompletionStage对应的子类? extends
* CompletionStage<U>,比如另一个CompletableFuture#supplyAsync返回值就是.
*/
@Test
public void thenComposeTest() {
CompletableFuture.supplyAsync(() -> getCurrentThreadName() + ": supplyAsync -> ")
.thenCompose(
(s) ->
CompletableFuture.supplyAsync(
() -> s + getCurrentThreadName() + "---theApply method -> "))
.thenAccept((f) -> System.out.println(f + getCurrentThreadName() + "---thenAccept"));
// ForkJoinPool.commonPool-worker-9: supplyAsync -> ForkJoinPool.commonPool-worker-9---theApply
// method -> main---thenAccept
}

3.7. CompletableFuture#thenCombine

/**
* @see CompletableFuture#thenCombine(CompletionStage, BiFunction)
* 等两个CompletableFuture完成后,对它们的返回值进行处理,也是对多个CompletableFuture进行组合
*/
@Test
public void thenCombineTest() {
CompletableFuture.supplyAsync(() -> getCurrentThreadName() + ": the first return value")
.thenCombine(
CompletableFuture.supplyAsync(
() -> getCurrentThreadName() + ": the second return value"),
(p1, p2) -> {
if (StringUtils.hasText(p1) && StringUtils.hasText(p2)) {
return p1 + "\n" + p2 + "\n";
} else if (StringUtils.hasText(p1)) {
return p1;
} else if (StringUtils.hasText(p2)) {
return p2;
} else {
return null;
}
})
.thenAccept((f) -> System.out.println(f + getCurrentThreadName() + "---thenAccept"));
// ForkJoinPool.commonPool-worker-9: the first return value
// ForkJoinPool.commonPool-worker-9: the second return value
// main---thenAccept
}

3.8. CompletableFuture#allOf

/**
* 多个CompletableFuture,如果都结束了,就可以获得它们的返回值,进行处理
*
* @throws InterruptedException
* @see CompletableFuture#allOf(CompletableFuture[])
*/
@Test
public void allOfTest() throws InterruptedException {
CompletableFuture<String> diligent =
CompletableFuture.supplyAsync(
() -> {
try {
TimeUnit.MICROSECONDS.sleep(100);
return getCurrentThreadName() + ": be a diligent man.";
} catch (InterruptedException e) {
e.printStackTrace();
return getCurrentThreadName() + ": missing diligent";
}
}); CompletableFuture<String> studious =
CompletableFuture.supplyAsync(
() -> {
try {
TimeUnit.MICROSECONDS.sleep(100);
return getCurrentThreadName() + ": be a studious man.";
} catch (InterruptedException e) {
e.printStackTrace();
return getCurrentThreadName() + ": missing studious";
}
}); CompletableFuture<String> savvy =
CompletableFuture.supplyAsync(
() -> {
try {
TimeUnit.MICROSECONDS.sleep(100);
return getCurrentThreadName() + ": be a savvy man.";
} catch (InterruptedException e) {
e.printStackTrace();
return getCurrentThreadName() + ": missing savvy";
}
}); CompletableFuture<List<String>> allOf =
CompletableFuture.allOf(savvy, diligent, studious)
.thenApply(
(n) -> {
return Stream.of(savvy, diligent, studious)
.map(
(completableFuture) -> {
try {
// get every return string
return completableFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return e.toString();
}
})
.collect(Collectors.toList());
}); TimeUnit.SECONDS.sleep(1);
// if you want to output every string (and above code of block of "thenApply" also can
// forEach(System.out::println))
allOf.thenAccept((stringList) -> stringList.forEach(System.out::println));
// ForkJoinPool.commonPool-worker-11: be a savvy man.
// ForkJoinPool.commonPool-worker-9: be a diligent man.
// ForkJoinPool.commonPool-worker-2: be a studious man. }

3.9. CompletableFuture#anyOf

/**
* anyOf方法,组合多个future,只要有一个结束就完成
*
* @see CompletableFuture#anyOf(CompletableFuture[])
*/
@Test
public void anyOfTest() {
CompletableFuture<People> peopleCompletableFuture = CompletableFuture.supplyAsync(People::new);
CompletableFuture<String> stringCompletableFuture =
CompletableFuture.supplyAsync(() -> "a string");
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> 1); CompletableFuture.anyOf(
stringCompletableFuture, peopleCompletableFuture, integerCompletableFuture)
.thenAccept(System.out::println);
}

3.10. CompletableFuture#handle

/**
* handle方法无论是否发生异常,都会调用,可以在这里处理异常,另一个处理异常的方式:{@link #exceptionallyTest()}
*
* @see CompletableFuture#handle(BiFunction)
* @throws InterruptedException
*/
@Test
public void handleTest() throws InterruptedException {
final String string = "";
CompletableFuture.supplyAsync(
() -> {
if (!StringUtils.hasText(string)) {
throw new NullPointerException("string is null");
}
return string;
})
.handle(
(s, t) -> {
if (t != null) {
// log.error("handle method", t);
log.error("handle method");
}
return s;
}); // For junit main thread stop after ForkJoinPool thread
TimeUnit.SECONDS.sleep(1);
System.out.println(getCurrentThreadName() + " stop");
// 18:30:47.837 [ForkJoinPool.commonPool-worker-9] ERROR
// com.xy.java.basic.demos.completablefuture.CompletableFutureTest - handle method
// main stop
}

3.11. Completable#exceptionally

/**
* 当发生异常时,进入exceptionally方法,另一个处理异常的方式:{@link #handleTest()}
*
* @see CompletableFuture#exceptionally(Function)
* @throws InterruptedException
* @throws ExecutionException
*/
@Test
public void exceptionallyTest() throws InterruptedException, ExecutionException {
final String string = "";
CompletableFuture.supplyAsync(
() -> {
if (!StringUtils.hasText(string)) {
throw new NullPointerException("string is null");
}
return Optional.ofNullable(string);
})
.exceptionally(
(t) -> {
// log.error("exceptionally method", t);
log.error("exceptionally method");
return Optional.empty();
}); // For junit main thread stop after ForkJoinPool thread
TimeUnit.SECONDS.sleep(1);
System.out.println(getCurrentThreadName() + " stop");
// 18:27:29.451 [ForkJoinPool.commonPool-worker-9] ERROR
// com.xy.java.basic.demos.completablefuture.CompletableFutureTest - exceptionally method
// main stop
}

3.12. CompletableFuture#complete

/**
* 手动完成一个耗时很长的Future,并且设置默认值
*
* @throws InterruptedException
* @throws ExecutionException
*/
@Test
public void completeTest() throws InterruptedException, ExecutionException {
CompletableFuture<Boolean> runAsync =
CompletableFuture.supplyAsync(
() -> {
try {
TimeUnit.SECONDS.sleep(3);
return true;
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}); TimeUnit.SECONDS.sleep(1);
// 手动设置Future为完成状态并设置默认值
runAsync.complete(false); System.out.println(runAsync.get());
// false TimeUnit.SECONDS.sleep(5);
}

3.13. 注:Junit测试类中的公共方法

private Thread getCurrentThread() {

        return Thread.currentThread();

    }

    private String getCurrentThreadName() {

        return getCurrentThread().getName();

    }

4. thenApply与thenCompose的区别

4.1. 用thenApply方法来组合两个CompletableFuture

/**
* @see CompletableFuture#thenApply(Function)
* 如果想用thenApply方法来组合两个CompletableFuture,看起来会非常不优雅,所以组合多个CompletableFuture推荐使用<b>CompletableFuture#thenCompose</b>
*/
@Test
public void thenApplyNeedReturnCompletionStageTest() {
CompletableFuture<Void> voidCompletableFuture =
CompletableFuture.supplyAsync(() -> getCurrentThreadName() + "---supplyAsync method -> ")
.thenApply(
(s) ->
CompletableFuture.supplyAsync(
() -> s + getCurrentThreadName() + "---theApply method -> "))
.thenAccept(
(c) ->
c.thenAccept(
(f) -> System.out.println(f + getCurrentThreadName() + "---thenAccept")));
// ForkJoinPool.commonPool-worker-9---supplyAsync method ->
// ForkJoinPool.commonPool-worker-9---theApply method -> main---thenAccept
}

4.2. 用thenCompose方法来组合两个CompletableFuture

/**
* @see CompletableFuture#thenCompose(Function) 作为两个CompletableFuture组合使用 这里的Function<? super T, ?
* extends CompletionStage<U>> T要转换成CompletionStage对应的子类? extends
* CompletionStage<U>,比如另一个CompletableFuture#supplyAsync返回值就是.
*/
@Test
public void thenComposeTest() {
CompletableFuture.supplyAsync(() -> getCurrentThreadName() + ": supplyAsync -> ")
.thenCompose(
(s) ->
CompletableFuture.supplyAsync(
() -> s + getCurrentThreadName() + "---theApply method -> "))
.thenAccept((f) -> System.out.println(f + getCurrentThreadName() + "---thenAccept"));
// ForkJoinPool.commonPool-worker-9: supplyAsync -> ForkJoinPool.commonPool-worker-9---theApply
// method -> main---thenAccept
}

5. CompletableFuture常用方法总结

1 runAsync接收的Runnable参数,supplyAsync接收的Supplier参数
2 thenAccept与thenAcceptAsync的区别在于:该callback方法是否在当前线程中执行(更具体的例子见前面的代码中的运行结果)
3 thenApply与thenCompose主要区别在于组合多个CompletableFuture
4 其他的方法如上面的代码例子所示

CompletableFuture的使用例子的更多相关文章

  1. CompletableFuture引入

    一.Future介绍 Future以前我们如果有个方法action执行,比如去数据库中查询数据.上传一个文件等,这个方法执行10分钟,调用者就需要等10分钟.基于此,调用者可以先执行action,返回 ...

  2. java8中CompletableFuture的使用介绍

    既然CompletableFuture类实现了CompletionStage接口,首先我们需要理解这个接口的契约.它代表了一个特定的计算的阶段,可以同步或者异步的被完成.你可以把它看成一个计算流水线上 ...

  3. Vertx简介

    今天看了一篇很不错的关于Vertx的简介,转载下. 原文链接:http://www.csdn.net/article/2015-12-21/2826533?utm_source=tuicool& ...

  4. Monad 在实际开发中的应用

    版权归作者所有,任何形式转载请联系作者. 作者:tison(来自豆瓣) 来源:https://www.douban.com/note/733279598/ Monad 在实际开发中的应用 不同的人会从 ...

  5. Java CompletableFuture 详解

    Future是Java 5添加的类,用来描述一个异步计算的结果.你可以使用isDone方法检查计算是否完成,或者使用get阻塞住调用线程,直到计算完成返回结果,你也可以使用cancel方法停止任务的执 ...

  6. CompletableFuture基本用法

    异步计算 所谓异步调用其实就是实现一个可无需等待被调用函数的返回值而让操作继续运行的方法.在 Java 语言中,简单的讲就是另启一个线程来完成调用中的部分计算,使调用继续运行或返回,而不需要等待计算结 ...

  7. 从CompletableFuture到异步编程设计

    从CompletableFuture到异步编程设计,笔者就分为2部分来分享CompletableFuture异步编程设计,前半部分总结下CompletableFuture使用实践,后半部分分享下Com ...

  8. JAVA8给我带了什么——Optional和CompletableFuture

    不管是JAVA,还是.NET.我们常常会看到空异常(NullPointerException).这种异常都是在运行的过程中出现.往往是变量是一个null值.但是你引用这个变量的后继字段或是方法.所以我 ...

  9. Java8 CompletableFuture

    http://colobu.com/2016/02/29/Java-CompletableFuture/ http://www.deadcoderising.com/java8-writing-asy ...

随机推荐

  1. 9. 弹出键盘挡住input

    1.) react 中 <input className="inp3" placeholder="密码" type="password" ...

  2. 华为鲲鹏服务器安装 k3s+rancher

    华为鲲鹏服务器安装 k3s+rancher 华为鲲鹏服务器 华为鲲鹏服务器采用华为自研cpu ARMv8架构,提供 Windows 和多个Linux 系统,作为服务器使用我一直使用Centos系统(不 ...

  3. orcale 树形结构查询

    接到需求是要在一个表中(表结构为主键id和父id)循环显示数据,类似于省市县++这种情况  也可能不只有三级子菜单 id  name   parentid 1     a          0 2  ...

  4. ES[7.6.x]学习笔记(三)新建索引

    与ES的交互方式 与es的交互方式采用http的请求方式,请求的格式如下: curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT& ...

  5. 架构设计 | 分布式业务系统中,全局ID生成策略

    本文源码:GitHub·点这里 || GitEE·点这里 一.全局ID简介 在实际的开发中,几乎所有的业务场景产生的数据,都需要一个唯一ID作为核心标识,用来流程化管理.比如常见的: 订单:order ...

  6. shll脚本常用格式和规则使用

    shll脚本格式和规则 脚本文件必须已 .sh 结尾(yuan.sh) 脚本第一行必须是:#!/bin/bash 激活脚本的二种方式(sh yuan.sh)(给脚本X权限,以绝对路径执行脚本) 逻辑与 ...

  7. Makefile 头文件 <> 与 "" 的差别,与 Visual Studio 不同

    #include "" : 首先在所有被编译的.c所在的路径中,查找头文件,如果找不到,则到 -I路径下去找头文件 #inclue <> :首先在-I路径下去找,如果找 ...

  8. Github C 编译器项目 8cc main函数中用到的 C库函数

    atexit C 库函数 int atexit(void (*func)(void)) 当程序正常终止时,调用指定的函数 func.您可以在任何地方注册你的终止函数,但它会在程序终止的时候被调用. s ...

  9. history of program atan2(y,x)和pow(x,y)

    编年史 1951 – Regional Assembly Language 1952 – Autocode 1954 – IPL (LISP语言的祖先) 1955 – FLOW-MATIC (COBO ...

  10. 使用@vue/cli搭建vue项目开发环境

    当前系统版本 mac OS 10.14.2 1.安装node.js开发环境 前端开发框架和环境都是需要 Node.js  vue的运行是要依赖于node的npm的管理工具来实现 <mac OS ...