当前位置:首页 > SEO优化 > 正文

代码优化的方法(table的基本组成)

    本文详细解释了java8中CompletableFuture的特性、方法和示例。  

  

    在java8之前,我们使用java的多线程编程,这通常是通过Runnable中的run方法来完成的。这种方法有一个明显的缺点,就是没有返回值。这时候大家可以尝试使用Callable中的call方法,然后用Future返回结果,如下:  

  

    通过观察控制台,我们发现先打印主线程,一秒钟后打印异步线程看起来是符合我们的需求的,但是仔细考虑之后发现了一个问题。调用future的get()方法时,当前主线程被阻塞,这似乎不是我们想看到的。另一种得到返回结果的方法是先轮询,可以叫isDone,但这并不能让我们满意。  

  

    无论如何,这种用法看起来并不优雅,至少从视觉,来看很难看,有些场景是不能用的,比如,  

  

    1.很多异步线程的执行时间可能不一致,所以我的主线程业务不能一直等下去。此时,我可能想等待最快的线程完成执行或最重要的任务完成执行,或者我只等待1秒钟。至于没有返回结果的线程,我将改用默认值。  

  

    2.执行在我的两个异步任务之间是独立的,但是第二个任务依赖于第一个任务的执行结果。  

  

    java8的CompletableFuture已经在这个混乱不完善的多线程江湖中出道了。CompletableFuture极大地改进和扩展了Future的功能和使用场景,提供了函数式编程能力,并使代码更加美观和优雅。此外,处理结果可以通过回调来计算,对于异常的处理有更好的处理方法  

  

    在执行异步任务:的完整的未来源代码中有四个静态方法  

  

    [  

  

    [  

  

    如果有多线程的基础知识,我们很容易看到,run开始时的两个方法是用于执行没有返回值的任务,因为它的输入是Runnable对象,而supply开始时的方法显然是执行有返回值的任务。如果执行器对象没有传入,那么ForkJoinPool.commonPool()将被用作它的线程池执行异步代码。在实际使用中,我们通常使用自己的线程池对象作为参数传入,这样比较快。  

  

    执行的异步任务模式也很简单,只需要用上面的方法就可以:  

  

    接下来,让我们看看获得执行结果的几种方法。  

  

    以上两种方法在Future中实现,get()会阻塞当前线程,造成问题。如果执行线程长时间不返回数据,get()将一直等待,因此第二个get()方法可以设置等待时间。  

  

    getNow()方法更有意思,就是返回结果的时候会返回结果,如果异步线程抛出异常,会返回自己设置的默认值。  

  

    接下来,我们将通过一些场景示例介绍CompletableFuture中其他一些常用的方法。  

  

    功能:在执行,正常完成当前任务后,当前任务的执行结果可以作为下一个任务的输入参数,没有返回值。  

  

    场景:执行任务A和执行任务B异步,任务B正常返回后,执行任务C返回值为B,任务C没有返回值  

  

    [  

  

    [  

  

    功能:不关心上一步的计算结果,执行下一步操作  

  

    场景:执行任务A,执行,执行任务B之后,任务B不接受任务A的返回值(不管A有没有返回值),没有返回值  

  

    功能:当前任务正常完成后,执行,当前任务的执行结果将作为下一个任务的输入参数,带有返回值  

  

    场景:任务与执行,和执行串联,下一个任务取决于前一个任务的结果,并且每个任务都有输入和输出  

  

    例1:异步执行任务a,当任务a完成时,用任务a的返回结果a作为输入,执行任务b的处理,可以实现任意数量任务的串行执行  

  

    [  

  

    [  

  

    有了上面的代码,当然可以调用future.join()先得到任务A的返回值,然后把返回值作为执行任务b的输入,应用的存在就是帮我简化这一步。我们不必因为等待计算完成而一直阻塞调用线程,而是告诉CompletableFuture在执行完成时继续下一步,并串联多个任务。  

  

    [  

  

    [  

  

    功能:合并了两个CompletionStage的结果,并在转换后返回  

  

    场景:需要根据商品id查询商品的当前价格。查询商品的原价格和折扣分两步。这两个查询相互独立。当两者都被发现时,原始的价格乘以折扣来计算当前的价格使用方法:  

  

    [  

  

    [  

  

    然后组合(…)将两个任务的返回值组合起来,然后返回它们。如果不需要返回,那么就需要nacceptbit (…)。同样,如果您不关心两个任务的返回值,您需要在两者之后运行。如果你理解了以上三种方法,然后应用,然后接受,然后运行,这里就不需要分别提到这两种方法了。  

  

    功能:这个方法接收的输入是当前的Complet  

ableFuture的计算值,返回结果将是一个新的CompletableFuture

  

    这个方法和thenApply非常像,都是接受上一个任务的结果作为入参,执行自己的操作,然后返回.那具体有什么区别呢?

  

    thenApply():它的功能相当于将CompletableFuture转换成CompletableFuture,改变的是同一个*CompletableFuture中的泛型类型*

  

    *thenCompose():用来连接两个CompletableFuture,返回值是一个新的CompletableFuture*

  

    [

  

    [

  

    这段代码实现的和上面thenApply一样的效果,在实际使用中,我并没有很清楚两个在使用上的区别,如果有大佬,跪求告知.

  

    功能:执行两个CompletionStage的结果,那个先执行完了,就是用哪个的返回值进行下一步操作

  

    场景:假设查询商品a,有两种方式,A和B,但是A和B的执行速度不一样,我们希望哪个先返回就用那个的返回值.

  

    [

  

    [

  

    同样的道理,applyToEither的兄弟方法还有acceptEither(),runAfterEither(),我想不需要我解释你也知道该怎么用了.

  

    功能:当运行出现异常时,调用该方法可进行一些补偿操作,如设置默认值.

  

    场景:异步执行任务A获取结果,如果任务A执行过程中抛出异常,则使用默认值100返回.

  

    [

  

    [

  

    上面代码展示了正常流程和出现异常的情况,可以理解成catch,根据返回值可以体会下.

  

    功能:当CompletableFuture的计算结果完成,或者抛出异常的时候,都可以进入whenComplete方法执行,举个栗子

  

    [

  

    [

  

    根据控制台,我们可以看出执行流程是这样,supplyAsync->whenComplete->exceptionally,可以看出并没有进入thenApply执行,原因也显而易见,在supplyAsync中出现了异常,thenApply只有当正常返回时才会去执行.而whenComplete不管是否正常执行,还要注意一点,whenComplete是没有返回值的.

  

    上面代码我们使用了函数式的编程风格并且先调用whenComplete再调用exceptionally,如果我们先调用exceptionally,再调用whenComplete会发生什么呢,我们看一下:

  

    [

  

    [

  

    代码先执行了exceptionally后执行whenComplete,可以发现,由于在exceptionally中对异常进行了处理,并返回了默认值,whenComplete中接收到的结果是一个正常的结果,被exceptionally美化过的结果,这一点需要留意一下.

  

    功能:当CompletableFuture的计算结果完成,或者抛出异常的时候,可以通过handle方法对结果进行处理

  

    [

  

    [

  

    通过控制台,我们可以看出,最后打印的是handle result:futureA result: 100,执行exceptionally后对异常进行了"美化",返回了默认值,那么handle得到的就是一个正常的返回,我们再试下,先调用handle再调用exceptionally的情况.

  

    [

  

    [

  

    根据控制台输出,可以看到先执行handle,打印了异常信息,并对接过设置了默认值500,exceptionally并没有执行,因为它得到的是handle返回给它的值,由此我们大概推测handle和whenComplete的区别

  

    1.都是对结果进行处理,handle有返回值,whenComplete没有返回值

  

    2.由于1的存在,使得handle多了一个特性,可在handle里实现exceptionally的功能

  

    allOf:当所有的都执行完后执行计算

  

    anyOf:最快的那个CompletableFuture执行完之后执行计算

  

    场景二:查询一个商品详情,需要分别去查商品信息,卖家信息,库存信息,订单信息等,这些查询相互独立,在不同的服务上,假设每个查询都需要一到两秒钟,要求总体查询时间小于2秒.

  

    [

  

    [

  

    参考资料:

  

    https://colobu.com/2016/02/29/Java-CompletableFuture/#Either

  

    https://blog.csdn.net/qq_36597450/article/details/81232051

有话要说...