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. CISCN love_math和roarctf的easy_clac学习分析

    Love_math 题目源码: <?php error_reporting(0); //听说你很喜欢数学,不知道你是否爱它胜过爱flag if(!isset($_GET['c'])){ show ...

  2. Java环境下 selenium webDriver + chrome浏览器搭建与调试

    一.首先下载selenium webDriver jar包,下载地址如下: http://selenium-release.storage.googleapis.com/index.html 二.下载 ...

  3. Springboot:logback日志管理(九)

    Springboot默认使用的日志框架就是logback 创建自定义的logback-spring.xml放在resources类目录下即可 logback-spring.xml: <?xml ...

  4. Codeforces 1340B Nastya and Scoreboard(dp,贪心)

    题目链接OvO 题目大意   给你\(n\)串数字,\(1\)代表该位置是亮的,\(0\)代表是灭的.你必须修改\(k\)个数字,使某些\(0\)变为\(1\).注意,只能把原来的\(0\)改成\(1 ...

  5. 递归复制&查看文件夹下的指定后缀的文件

    <?php header("content-type:text/html;charset=utf8"); set_time_limit(0); $dir = "d: ...

  6. python学习13类2之封装

    '''''''''面向对象三大特性:封装,继承,多态1.封装: 类中以_或者__的属性,都是私有属性,禁止外部调用.'''class Student(object): def __init__(sel ...

  7. HTML入门——互动式推送初尝试

    0.背景 疫情原因,导致许多大众喜闻乐见的体育活动停摆,但博主和队友们运营的体育社团公众号不能停摆.为了利用当下线上活动频率高的契机增加关注量,加之微信推送的互动性已成为趋势,博主打算和队友们尝试实现 ...

  8. sed命令的正则表达式实践

    1. 取系统ip [root@oldboy logs]# ifconfig eth3 eth3 Link encap:Ethernet HWaddr 08:00:27:4C:6F:AD inet ad ...

  9. TCP连接过程及报文解析

    可能大家都听过TCP建立连接时需要经历三次握手和四次挥手的. 那么具体的握手挥手的过程是怎么样的呢? 这篇文章就通过WireShark抓包来了解TCP连接建立和断开的过程. 实验方法: 写一段简单的代 ...

  10. Centos7 team 绑定多网卡

    1.nmcli connection show 查看所有的网络连接 nmcli connection show 接下来我们要使用 ens37 ens38 两个网卡绑定 , 绑定的网卡取名: agg-e ...