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. python 基础篇 模块化

    在做项目的时候,虽然你不可能把全世界的代码都放到一个文件夹下,但是类似模块化的思想还是要有的--那就是以项目的根目录作为最基本的目录,所有的模块调用,都要通过根目录一层层向下索引的方式来 import ...

  2. 纯css画三角形

    纯css画三角形与border元素相关 设置border的属性 width: 100px; height: 100px; border-style: solid; border-width: 100p ...

  3. Java的数组索引问题

    /* 数组操作的两个常见小问题: ArrayIndexOutOfBoundsException:数组索引越界异常 原因:你访问了不存在的索引. NullPointerException:空指针异常 原 ...

  4. Ubuntu16.04 安装eclipse

    首先确保自己的Ubuntu已经安装了jdk并且配置好了环境变量 然后在官网下载相应的eclipse安装包: https://www.eclipse.org/downloads/packages/ 下载 ...

  5. curl发送多维数组

    //通过curl模拟post的请求: function SendDataByCurl($url,$data=array()){ //对空格进行转义 $url = str_replace(' ','+' ...

  6. MySQL的远程链接

    安装好我们的mMySQL,是不是也有种无从下手的感觉,不用怕,接下来我们可以使用远程连接来可视化我们的数据库的数据: 1. 打开我们的数据库,帐号是root,密码查看文件就行了 2.使用命令: mys ...

  7. PHP open_basedir配置未包含upload_tmp_dir 导致服务器不能上传文件

    在做一个上传图片的功能时候发现后台接收到的$_FILES['file']['error'] = 6,这个错误意思是找不到临时文件,或者是临时文件夹无权限,需要更改php.ini文件的 upload_t ...

  8. 2019-2020-1 20199310《Linux内核原理与分析》第七周作业

    1.问题描述 在前面的文章中,学习了系统调用system_call的处理过程,在MenuOS中运行getpid命令,通过gdb跟踪调用time函数的过程,并分析system_call代码对应的工作过程 ...

  9. KafkaConsumer assign VS subscribe

    背景 在kafka中,正常情况下,同一个group.id下的不同消费者不会消费同样的partition,也即某个partition在任何时刻都只能被具有相同group.id的consumer中的一个消 ...

  10. 使用cpplint检测代码规范

    0. cpplint - python脚本, google使用它作为自己的C++代码规范检查工具: 1. 安装 方法一: $sudo apt-get install python-pip $pip i ...