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. 不借助多余参数也可交换两个参数(c++,swap函数)

    利用a^a=0异或属性 [示例代码] #include<stdio.h> void data_swap(int &a,int &b){ a = a ^ b; b = a ^ ...

  2. 小白初学Java的一点点收获

    作为刚刚学习Java没有几天的小白,我想把我在学习过程中,所学习到的知识和注意事项和大家一起分享分享.在这个过程中,希望大家可以有所收获,有什么不对的地方,希望大家指出并且私信我. 首先说说第一次记事 ...

  3. vim环境下空格和tab键互换

    对于已保存的文件,可以使用下面的方法进行空格和TAB的替换 TAB替换为空格::set ts=4:set expandtab:%retab! 空格替换为TAB::set ts=4:set noexpa ...

  4. 【已解决】error setting certificate verify locations报错

    目录 1.问题描述 2.问题分析 3.解决方法 1.问题描述 在公司的电脑上从Github上clone项目的时候git黑窗口报错"error setting certificate veri ...

  5. jquery选择时分插件

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

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

    第七周作业 1.进程描述符task_struct数据结构(一) 为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息. struct task_struct数据结构很 ...

  7. linux find string in files

    http://blog.csdn.net/duguduchong/article/details/7716908 查找目录下的所有文件中是否含有某个字符串 find .|xargs grep -ri ...

  8. 利用python将excel数据导入mySQL

    主要用到的库有xlrd和pymysql, 注意pymysql不支持python3 篇幅有限,只针对主要操作进行说明 连接数据库 首先pymysql需要连接数据库,我这里连接的是本地数据库(数据库叫ld ...

  9. Android Resourse

    为什么80%的码农都做不了架构师?>>>   使用情景: 实现帧动画步骤的控制,这样动态的获取Drawable资源对应的R id,播放到那一步就加载到哪一步 private void ...

  10. Vue 结合 echarts 原生 html5 实现拖拽排版报表系统

    前言 不知道各位 coder 有没有碰到过许多重复的业务需求,比如排版相类似的报表,只不过是顺序稍微换了一下,就是一个新的页面,虽然基于模板思想来写的话也能减少不少代码,但是相对的不那么方便,笔者最近 ...