zoukankan      html  css  js  c++  java
  • 学习使用CompletableFuture

    一.前言

    1.JDK5的异步处理方式

    在jdk5中,我们通过使用Future和Callable,可以在任务执行完毕后得到任务执行结果,可以使用isDone检测计算是否完成,使用cancle停止执行任务,使用阻塞方法get阻塞住调用线程来获取返回结果。但通过使用阻塞方式来获取执行结果,有两方面弊端,一是违异步编程的初衷,二是Future的异常只能自己内部处理。

    2.JDK8的异步处理方式

    jdk8中加入了实现类CompletableFuture,用于异步编程。底层做任务使用的是ForkJoin, 顾名思义,是将任务的数据集分为多个子数据集,而每个子集,都可以由独立的子任务来处理,最后将每个子任务的结果汇集起来。它是ExecutorService接口的一个实现,它把子任务分配给线程池(称为ForkJoinPool)中的工作线程。从api文档看,它实现了2个接口CompletionStage和Future。CompletionStage支持lambda表达式,接口的方法的功能都是在某个阶段得到结果后要做的事情。因此,CompletableFuture不仅拥有Future的所有特性,而且还内置了lambda表达式,支持异步回调,结果转换等功能,它有以下Future实现不了的功能:

    1)合并两个相互独立的异步计算的结果

    2)等待异步任务的所有任务都完成

    3)等待异步任务的其中一个任务完成就返回结果

    4)任务完成后调用回调方法

    5)任务完成的结果可以用于下一个任务。

    6)任务完成时发出通知

    7)提供原生的异常处理api

    二、学习CompletableFuture

    1.结果获取方式

    CompletableFuture获取结果的方式有如下四个方法:

    1)get 阻塞获取结果,实现Future的get接口,显式抛出异常

    2)getNow(T valueIfAbsent) 获取执行结果,如果当前任务未执行完成,则返回valueIfAbsent

    3)join 执行完成后返回执行结果,或者抛出unchecked异常

    4)T get(long timeout, TimeUnit unit) 在有限时间内获取数据

    2.创建CompletableFuture对象

    1)通过静态方法获取对象
    ​​​​​​​​​​​​​​在这里插入图片描述
    这是一个静态方法,返回一个已经计算好的CompletableFuture,示例如下:
    在这里插入图片描述
    completableFuture还能主动结束运算,并显示处理异常,如下是异步执行的代码:
    在这里插入图片描述
    2)使用工厂方式创建CompletableFuture对象

    CompletableFuture主要有以下四个工厂方式创建对象的静态方法:
    在这里插入图片描述
    Supplier是java8函数式编程的一个接口,是一个生产者,可以不接收参数。只有一个get方法返回一个泛型实例。很明显,Async结尾的都是可以异步执行,runAsync接收一个Runnable函数式接口类型参数,不返回计算结果。supplyAsync接收一个函数式接口类型Supplier,可以返回计算结果。以上方法如果不指定执行任务的线程池Executor,则默认使用ForkJoinPool.commonPoolcommonPool执行任务。这些接口都支持lambda实现异步的操作。以下是SupplyAsync异步执行的简单示例:
    在这里插入图片描述

    3.CompletableFuture 的异步回调功能:thenApply

    上面的方法,执行任务是异步操作。但是调用线程还在等待结果。我们还可以给cf添加回调方法,在任务执行完成后使用cf的结果再做下一步操作、转换。所以执行以下方法时,cf已经计算完毕。
    在这里插入图片描述
    从参数类型可以看到,这是接收一个cf计算的结果T,经过处理后返回参数类型为U的cf。 其中第一个方法是在cf完成的线程中调用。而带Async将在与调用者cf不同的线程中异步调用。
    在这里插入图片描述

    4.运行完成时的代码,即对结果进行消耗:thenAccept

    在这里插入图片描述
    入参是Consumer,执行Consumer后没有返回结果,所以称为消耗。
    在这里插入图片描述
    结果:a

    5.上一步结果与下一步操作无关系:thenRun

    在执行cf后,如果得到的结果对下一步没有影响,也就是说下一步的操作并不关心上一步的结果,最终也不返回值,可以使用thenRun,参数传递一个Runnable。
    在这里插入图片描述
    在这里插入图片描述

    6.对2个cf的结果进行组合:thenCompose

    在这里插入图片描述
    thenCompose方法可以将2个独立的任务进行流水线操作。将当前cf的计算结果作为参数传递给后面的cf。
    在这里插入图片描述

    7.结合2个cf的结果:thenCombine

    可以将两个完全不相干的对象的结果整合起来,两项任务可以同时执行,比如一个对外的接口服务,既查询数据库中要查询数据的总量,也要返回具体某一页的数据,可以一个cf负责执行查询总条数count的sql,一个查询一页数据。BiFunction是合并结果数据的函数:
    在这里插入图片描述
    其中T是调用thenCombine的cf的结果数据,U是other的结果,v就是合并的结果类型。
    在这里插入图片描述

    8.消耗两个cf的结果,不返回结果

    在这里插入图片描述
    对于2个cf,我们只想在他们执行完成时,消耗执行结果,但是不做数据返回,我们只是希望当完成时得到通知,此方法与thenCombine相似,只不过返回 CompletableFuture,只做消耗处理。
    在这里插入图片描述

    9.取计算速度最快的结果:acceptEither

    针对两个CompletionStage,将计算最快的那个CompletionStage的结果用来作为下一步的消耗。此方法接受Consumer只对结果进行消耗。
    在这里插入图片描述
    在这里插入图片描述

    10.计算最快的cf的结果转换:applyToEither

    针对两个CompletionStage,将计算的快的那个CompletionStage的结果用来作为下一步的转换操作。
    在这里插入图片描述
    fn是对调用applyToEither的调用者和计算最快的那个结果进行处理,传入t类型数据,返回一个CompletionStage。
    在这里插入图片描述

    11.2个cf都执行完后执行操作:runAfterBoth

    2个cf都执行完后,执行操作Runnable。Runnable不关心2个cf的执行结果:
    在这里插入图片描述
    在这里插入图片描述

    12.处理cf数组:allOf / anyOf

    以上介绍的都是2个future的组合使用。cf还提供allOf,参数是cf数组,当数组中所有的cf都执行完成时,返回一个CompletableFuture。调用返回的cf的join方法阻塞等待cf数组中所有cf执行完成。anyOf是当cf数组中任意一个cf执行完成后,就返回一个cf。
    在这里插入图片描述

    13.异常处理

    在上面手工创建cf对象中,介绍过异常的处理,同样使用工厂创建的cf也具有异常管理机制,不在赘述。

  • 相关阅读:
    swift3.0更新内容
    Core Animation
    UIBezierPath精讲
    iOS-Core-Animation-Advanced-Techniques(原文来自cocoachina)
    iOS上图形和动画处理
    使用GCD(转自唐巧的技术博客)
    UITableView的cell的分割线位置
    swift深入理解闭包
    Swift控制器加载xib Swift Controller'view load from xib
    -[UIWindow viewForFirstBaselineLayout]: unrecognized selector sent to instance
  • 原文地址:https://www.cnblogs.com/ason-wxs/p/13386770.html
Copyright © 2011-2022 走看看