异步编程 - 05 基于JDK中的Future实现异步编程(中)_CompletableFuture2

简介: 异步编程 - 05 基于JDK中的Future实现异步编程(中)_CompletableFuture2

多个CompletableFuture进行组合运算


CompletableFuture功能强大的原因之一是其可以让两个或者多个Completable-Future进行运算来产生结果,下面我们来看其提供的几组函数:


1)基于thenCompose实现当一个CompletableFuture执行完毕后,执行另外一个CompletableFuture:

public class TestTwoCompletableFuture {
    // 1.异步任务,返回future
    public static CompletableFuture<String> doSomethingOne(String encodedCompanyId) {
        // 1.1创建异步任务
        return CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                // 1.1.1休眠1s,模拟任务计算
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 1.1.2 解密,并返回结果
                String id = encodedCompanyId;
                return id;
            }
        });
    }
    // 2.开启异步任务,返回future
    public static CompletableFuture<String> doSomethingTwo(String companyId) {
        return CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                // 2.1 休眠3s,模拟计算
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                // 2.2 查询公司信息,转换为str,并返回
                String str = companyId + ":alibaba";
                return str;
            }
        });
    }
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // I,等doSomethingOne执行完毕后,接着执行doSomethingTwo
        CompletableFuture result = doSomethingOne("123").thenCompose(id -> doSomethingTwo(id));
        System.out.println(result.get());
    }
}


上述main函数中首先调用方法doSomethingOne(“123”)开启了一个异步任务,并返回了对应的CompletableFuture对象,我们取名为future1,然后在future1的基础上调用了thenCompose方法,企图让future1执行完毕后,激活使用其结果作为doSomethingTwo(String companyId)方法的参数的任务。



2)基于thenCombine实现当两个并发运行的CompletableFuture任务都完成后,使用两者的结果作为参数再执行一个异步任务,这里只需要把上面例子中的:

CompletableFuture result = doSomethingOne("123").thenCompose(id -> doSomethingTwo(id));


修改为:

result = doSomethingOne("123").thenCombine(doSomethingTwo("456"), (one, two) -> {
            return one + " " + two;
        });


3)基于allOf等待多个并发运行的CompletableFuture任务执行完毕:

public static void allOf() throws InterruptedException, ExecutionException {
    // 1.创建future列表
    List<CompletableFuture<String>> futureList = new ArrayList<>();
    futureList.add(doSomethingOne("1"));
    futureList.add(doSomethingOne("2"));
    futureList.add(doSomethingOne("3"));
    futureList.add(doSomethingOne("4"));
    // 2.转换多个future为一个
    CompletableFuture<Void> result = CompletableFuture
            .allOf(futureList.toArray(new CompletableFuture[futureList.size()]));
    // 3.等待所有future都完成
    System.out.println(result.get());
}


如上代码1调用了四次doSomethingOne方法,分别返回一个CompletableFuture对象,然后收集这些CompletableFuture到futureList列表。


代码2调用allOf方法把多个CompletableFuture转换为一个result,代码3在result上调用get()方法会阻塞调用线程,直到futureList列表中所有任务执行完毕才返回。



4)基于anyOf等多个并发运行的CompletableFuture任务中有一个执行完毕就返回

public static void anyOf() throws InterruptedException, ExecutionException {
    // 1.创建future列表
    List<CompletableFuture<String>> futureList = new ArrayList<>();
    futureList.add(doSomethingOne("1"));
    futureList.add(doSomethingOne("2"));
    futureList.add(doSomethingTwo("3"));
    // 2.转换多个future为一个
    CompletableFuture<Object> result = CompletableFuture
            .anyOf(futureList.toArray(new CompletableFuture[futureList.size()]));
    // 3.等待某一个future完成
    System.out.println(result.get());
}

如上代码1调用了四次doSomethingOne方法,分别返回一个CompletableFuture对象,然后收集这些CompletableFuture到futureList列表。


代码2调用anyOf方法把多个CompletableFuture转换为一个result,代码3在result上调用get()方法会阻塞调用线程,直到futureList列表中有一个任务执行完毕才返回。




异常处理


前文的代码为我们演示的功能都是当异步任务内可以正常设置任务结果时的情况,但是情况并不总是这样的,比如下面这段代码:


public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
    // 1.创建一个CompletableFuture对象
    CompletableFuture<String> future = new CompletableFuture<String>();
    // 2.开启线程计算任务结果,并设置
    new Thread(() -> {
        // 2.1休眠3s,模拟任务计算
        try {
            // 2.1.1抛出异常
            if (true) {
                throw new RuntimeException("excetion test");
            }
            // 2.1.2设置正常结果
            future.complete("ok");
        } catch (Exception e) {
        }
        // 2.2设置计算结果到future
        System.out.println("----" + Thread.currentThread().getName() + " set future result----");
    }, "thread-1").start();
    // 3.等待计算结果
    System.out.println(future.get());
}


由上述代码可知,在代码2.1.2设置正常结果前,代码2.1.1抛出了异常,这会导致代码3一直阻塞,所以我们不仅需要考虑正常设置结果的情况,还需要考虑异常的情况,其实CompletableFuture提供了completeExceptionally方法来处理异常情况,将上述代码修改为如下所示。


public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
    // 1.创建一个CompletableFuture对象
    CompletableFuture<String> future = new CompletableFuture<String>();
    // 2.开启线程计算任务结果,并设置
    new Thread(() -> {
        // 2.1休眠3s,模拟任务计算
        try {
            // 2.1.1 抛出异常
            if (true) {
                throw new RuntimeException("excetion test");
            }
            // 2.1.2设置正常结果
            future.complete("ok");
        } catch (Exception e) {
            // 2.1.3 设置异常结果
            future.completeExceptionally(e);
        }
        // 2.2设置计算结果到future
        System.out.println("----" + Thread.currentThread().getName() + " set future result----");
    }, "thread-1").start();
    // 3.等待计算结果
    System.out.println(future.get());
}


如上代码2.1.3表示当出现异常时把异常信息设置到future内部,这样代码3就会在抛出异常后终止。


其实我们还可以修改代码3为:


System.out.println(future.exceptionally(t -> "default").get());// 默认值



实现当出现异常时返回默认值。

相关文章
|
监控 算法 Java
异步编程 - 05 基于JDK中的Future实现异步编程(中)_CompletableFuture
异步编程 - 05 基于JDK中的Future实现异步编程(中)_CompletableFuture
50 0
|
Java
异步编程 - 07 基于JDK中的Future实现异步编程(下)_当Stream遇见CompletableFuture
异步编程 - 07 基于JDK中的Future实现异步编程(下)_当Stream遇见CompletableFuture
73 0
|
Java
异步编程 - 06 基于JDK中的Future实现异步编程(中)_CompletableFuture源码解析
异步编程 - 06 基于JDK中的Future实现异步编程(中)_CompletableFuture源码解析
65 0
|
Java
异步编程 - 04 基于JDK中的Future实现异步编程(上)_Future & FutureTask 源码解析
异步编程 - 04 基于JDK中的Future实现异步编程(上)_Future & FutureTask 源码解析
81 0
|
消息中间件 网络协议 Java
JDK 伪异步编程(线程池)
伪异步IO编程 BIO主要的问题在于每当有一个新的客户端请求接入时,服务端必须创建一个新的线程处理新接入的客户端链路,一个线程只能处理一个客户端连接。在高性能服务器应用领域,往往需要面向成千上万个客户端的并发连接,这种模型显然无法满足高性能、高并发接入的场景。
1234 0
|
3月前
|
Java
安装JDK18没有JRE环境的解决办法
安装JDK18没有JRE环境的解决办法
378 3
|
4月前
|
Oracle Java 关系型数据库
Mac安装JDK1.8
Mac安装JDK1.8
770 4
|
4月前
|
Java 关系型数据库 MySQL
"解锁Java Web传奇之旅:从JDK1.8到Tomcat,再到MariaDB,一场跨越数据库的冒险安装盛宴,挑战你的技术极限!"
【8月更文挑战第19天】在Linux上搭建Java Web应用环境,需安装JDK 1.8、Tomcat及MariaDB。本指南详述了使用apt-get安装OpenJDK 1.8的方法,并验证其版本。接着下载与解压Tomcat至`/usr/local/`目录,并启动服务。最后,通过apt-get安装MariaDB,设置基本安全配置。完成这些步骤后,即可验证各组件的状态,为部署Java Web应用打下基础。
64 1
|
1月前
|
Oracle Java 关系型数据库
安装 JDK 时应该注意哪些问题
选择合适的JDK版本需考虑项目需求与兼容性,推荐使用LTS版本如JDK 17或21。安装时注意操作系统适配,配置环境变量PATH和JAVA_HOME,确保合法使用许可证,并进行安装后测试以验证JDK功能正常。
51 1
|
1月前
|
IDE Java 编译器
开发 Java 程序一定要安装 JDK 吗
开发Java程序通常需要安装JDK(Java Development Kit),因为它包含了编译、运行和调试Java程序所需的各种工具和环境。不过,某些集成开发环境(IDE)可能内置了JDK,或可使用在线Java编辑器,无需单独安装。
66 1