【蓝鸟和平源码】【钢琴识别源码】【智慧车站源码】线程池apply方法源码_线程池 源码

时间:2024-12-28 18:54:25 来源:内存源码 分类:焦点

1.Java 异步编程的线程线程完美利器:CompletableFuture 指北
2.奇*巧技,CompletableFuture 异步多线程是池a池源真的优雅
3.研发必会-异步编程利器之CompletableFuture(含源码 中)
4.源码细读-深入了解terser-webpack-plugin的实现
5.CompletableFuture详解
6.再谈CompletableFuture之循环创建并发线程

线程池apply方法源码_线程池 源码

Java 异步编程的完美利器:CompletableFuture 指北

       在Java异步编程领域,CompletableFuture是源码不可或缺的利器。本文旨在深入探讨CompletableFuture,线程线程以解答其为何能成为异步编程的池a池源完美解决方案。

       在讨论Future获取异步执行结果之前,源码蓝鸟和平源码我们先了解Future接口及其常用方法。线程线程Future接口提供了丰富的池a池源功能,包括取消任务、源码判断任务状态以及获取结果的线程线程方法。

       通过Future接口,池a池源我们能使用FutureTask类将Callable任务转化为可执行的源码异步任务,并在必要时获取任务结果。线程线程然而,池a池源Future与FutureTask在实际应用中存在不足,源码如缺乏异步回调机制、无法主动完成或取消任务、阻塞式获取结果以及异常处理的灵活性问题。

       为解决这些不足,Java引入了CompletableFuture,提供更丰富的功能,如异步回调、任务组合、时序依赖关系描述以及异常处理。CompletableFuture通过多种方法创建任务,如使用Runnable、Supplier接口,以及默认使用的ForkJoinPool线程池。

       在处理任务依赖关系时,CompletableFuture提供了描述串行、AND汇聚、OR汇聚以及异常处理的钢琴识别源码接口。通过thenApply、thenAccept、thenRun和thenCompose等方法,我们能清晰描述任务的串行执行关系。

       对于AND汇聚关系,我们可以使用thenCombine、thenAcceptBoth或runAfterBoth等接口;而对于OR汇聚关系,applyToEither、acceptEither或runAfterEither等接口则能实现这一目的。这些方法允许我们灵活地组合和处理异步任务。

       异常处理在异步编程中尤为重要,CompletableFuture通过简单易用的方法,如exceptionally、whenComplete和handle等,帮助我们捕获并处理异常。这些方法允许我们以链式编程的方式,优雅地处理异步操作中的异常情况。

       获取异步结果时,我们有多种选择,如get、join、whenComplete、handle、allOf和anyOf等方法。这些方法提供了灵活的接口,以适应不同的异步获取需求。例如,allOf方法允许我们在所有任务完成时触发操作,而anyOf方法则等待任意一个任务完成。

       通过以上内容,我们全面理解了CompletableFuture在Java异步编程中的智慧车站源码作用,它不仅解决了Future与FutureTask的不足,还提供了丰富的功能,以支持更复杂的异步编程场景。CompletableFuture是Java异步编程的完美利器,值得开发者深入研究和掌握。

奇*巧技,CompletableFuture 异步多线程是真的优雅

       在处理多线程异步任务时,Java的Future接口虽然提供了一定的异步执行能力,但获取结果的方式并不优雅。传统的Future.get()会导致线程阻塞,或通过轮询检查完成状态。当涉及到多个异步任务依赖时,CountDownLatch可以解决,但Java 8之后,CompletableFuture的引入带来了更为优雅的解决方案。

       CompletableFuture不仅能够轻松实现CountDownLatch的功能,还能实现更复杂的任务依赖和回调机制。比如,任务A完成后立即执行任务B,甚至任务A的结果可以作为任务B的参数。四种常见的创建方式,如supplyAsync和runAsync,提供了异步执行任务的不同途径。

       获取结果的方式也有四种,包括thenRun/thenRunAsync(无返回值回调)、thenAccept/thenAcceptAsync(回调方法接受结果,无返回)、thenApply/thenApplyAsync(回调方法接收结果并返回)、以及异常处理的whenComplete和exceptionally。它们允许在任务完成或出错时执行特定操作。

       多任务组合回调提供了AND和OR的mmm源码app关系,如thenCombine、applyToEither等,允许任务之间复杂的依赖关系。但需要注意,如果没有正确配置线程池,如使用默认的ForkJoin线程池,可能会导致性能问题或任务被丢弃。

       使用CompletableFuture时,还需注意Future获取返回值时可能的异常信息、get()方法的阻塞性、以及推荐使用自定义线程池和避免饱和策略导致的任务丢弃。这些细节将确保异步编程的高效和优雅。

研发必会-异步编程利器之CompletableFuture(含源码 中)

       微信公众号访问地址: 研发必会-异步编程利器之CompletableFuture(含源码 中)

       近期热推文章:

       1、springBoot对接kafka,批量、并发、异步获取消息,并动态、批量插入库表;

       2、SpringBoot用线程池ThreadPoolTaskExecutor异步处理百万级数据;

       3、基于Redis的Geo实现附近商铺搜索(含源码)

       4、基于Redis实现关注、取关、共同关注及消息推送(含源码)

       5、SpringBoot整合多数据源,并支持动态新增与切换(详细教程)

       6、基于Redis实现点赞及排行榜功能

       7、研发必会-异步编程利器之CompletableFuture(上)

       一、多任务组合回调

       备注:源码获取方式在文底。

       1.1、AND组合关系

       thenCombine / thenAcceptBoth / runAfterBoth都表示:将两个CompletableFuture组合起来,只有这两个都正常执行完了,才会执行某个任务。骑士电影 源码也即:当任务一和任务二都完成再执行任务三(异步任务)。

       区别在于:

       1、runAfterBoth:不会把执行结果当做方法入参,且没有返回值。

       2、thenAcceptBoth:会将两个任务的执行结果作为方法入参,传递到指定方法中,且无返回值。

       3、thenCombine:会将两个任务的执行结果作为方法入参,传递到指定方法中,且有返回值。

       代码案例:

       运行结果:

       1.2、OR组合关系

       将两个CompletableFuture组合起来,只要其中一个执行完了,就会执行某个任务。(两个任务,只要有一个任务完成,就执行任务三)

       区别在于:

       1、runAfterEither:不会把执行结果当做方法入参,且没有返回值。

       2、acceptEither: 会将已经执行完成的任务,作为方法入参,传递到指定方法中,且无返回值。

       3、applyToEither:会将已经执行完成的任务,作为方法入参,传递到指定方法中,且有返回值。(个人推荐)

       参考代码:

       返回结果:

       若将异步任务中的Thread.sleep()改为,将输出的结果为:

       从结果中不难对比发现,任务的参数是任务和任务中执行最快的返回结果。

       注意:若把核心线程数量改为1,会是什么样的呢?

       运行结果:

       从上面看出,改为1就变成单线程执行了。

       1.3、多任务组合(allOf\anyOf)

       1.allOf:等待所有任务都执行完成后,才会执行 allOf 返回的CompletableFuture。如果任意一个任务异常,allOf的CompletableFuture,执行get方法,会抛出异常。(等待所有任务完成才会执行)

       2.anyOf:任意一个任务执行完,就执行anyOf返回的CompletableFuture。如果执行的任务异常,anyOf的CompletableFuture,执行get方法,会抛出异常。(只要有一个任务完成)

       参考案例:

       结果返回:

       从结果中看出:等待所有任务都执行完成后,才会执行 allOf 返回的CompletableFuture。

       同理anyOf,只需要调整代码:

       运行结果:

       1.4、thenCompose

       thenCompose方法会在某个任务执行完成后,将该任务的执行结果,作为方法入参,去执行指定的方法。该方法会返回一个新的CompletableFuture实例。

       1、如果该CompletableFuture实例的result不为null,则返回一个基于该result新的CompletableFuture实例;

       2、如果该CompletableFuture实例为null,然后就执行这个新任务。

       代码案例:

       结果:

       二、使用注意点

       CompletableFuture 使异步编程更加便利的、代码更加优雅的同时,也要关注使用的一些注意点。

       2.1、Future需要获取返回值,才能获取异常信息

       代码案例:

       输出结果:

       Future需要获取返回值(res.get()),才能获取到异常信息。如果不加 get()/join()方法,看不到异常信息。使用的时候,注意一下,考虑是否加try…catch…或者使用exceptionally方法。

       若改成exceptionally方法,无需get或join也可以捕获异常信息:

       结果:

       2.2、CompletableFuture的get()方法是阻塞的

       CompletableFuture的get()方法是阻塞的,如果使用它来获取异步调用的返回值,需要添加超时时间。

       推荐使用:

       2.3、建议使用自定义线程池,不要使用默认的

       CompletableFuture代码中使用了默认的线程池,处理的线程个数是电脑CPU核数-1。在大量请求过来的时候,处理逻辑复杂的话,响应会很慢。一般建议使用自定义线程池,优化线程池配置参数。

       参考案例:

       但是如果线程池拒绝策略是DiscardPolicy或者DiscardOldestPolicy,当线程池饱和时,会直接丢弃任务,不会抛弃异常。因此建议,CompletableFuture线程池策略最好使用AbortPolicy,然后耗时的异步线程,做好线程池隔离。

       说明:

       AbortPolicy(默认):直接抛弃

       CallerRunsPolicy:用调用者的线程执行任务

       DiscardOldestPolicy:抛弃队列中最久的任务

       DiscardPolicy:抛弃当前任务。

       三、源码获取方式

       更多优秀文章,请关注个人微信公众号或搜索“程序猿小杨”查阅。然后回复:源码,可以获取对应的源码,开箱即可使用。

       如果大家对相关文章感兴趣,可以关注微信公众号"程序猿小杨",会持续更新优秀文章!欢迎大家 分享、收藏、点赞、在看,您的支持就是我坚持下去的最大动力!谢谢!

       参考网站:

       blog.csdn.net/ThinkWon/...

       mp.weixin.qq.com/s/shjA...

源码细读-深入了解terser-webpack-plugin的实现

       terser-webpack-plugin 是一个基于 webpack 的插件,它利用 terser 库对 JavaScript 代码进行压缩和混淆。其核心功能在于通过在 webpack 的运行时钩子 optimizeChunkAssets 中注册,实现了代码优化过程。在 apply 函数中,它获取 compilation 实例,并通过 tapPromise 注册一个异步任务,当 webpack 执行优化阶段时,每个 chunk 会触发这个任务,执行 minify 函数进行压缩处理。

       optimise 函数是实际的任务处理入口,它负责具体的优化流程。函数内部,scheduleTask 负责并行处理,如果开启 parallel 模式,会利用jest-worker提供的线程池进行并发工作,线程池管理复杂,根据 node 版本不同采用 worker_threads 或 child_process。minify 函数则是压缩和混淆代码的核心操作,它直接使用 terser 库完成任务。

       总的来说,terser-webpack-plugin 的优化流程包括在 webpack 的优化阶段对代码进行压缩,使用 Jest 的 worker 线程池进行并行处理,以及通过 terser 库的实际压缩操作。理解这些核心环节,可以帮助开发者更深入地掌握该插件的使用和工作原理。

CompletableFuture详解

       CompletableFuture详解

       CompletableFuture是Java中强大的并发工具,它在Future的基础上引入了流式编程和Lambda表达式,支持一元操作符、异步性和事件驱动模型,尤其在处理多线程关系上表现出色。相较于Future,CompletableFuture提供了更大的灵活性和功能。

       创建方式

       使用默认线程池:如`CompletableFuture future = new CompletableFuture>();`,默认采用ForkJoinPool.commonPool(),适用于非阻塞的CPU密集型任务。

       自定义线程池:用户可根据需要创建自定义线程池。

       操作示例

       - **异步任务**:

       runAsync:无返回值,处理数据但不返回结果。

       supplyAsync:有返回值,处理数据并返回结果。

       - **结果消费**:

       thenApply:有返回值,基于前一阶段结果执行操作。

       thenAccept:无返回值,只消费结果。

       thenRun:无返回值,与前一阶段同步执行。

       - **结果合并**:

       thenCombine:有返回值,结合另一个任务结果返回新结果。

       thenAcceptBoth:无返回值,等待第一个任务完成并传递结果。

       runAfterBoth:无返回值,两个任务并行执行。

       - **任一结果处理**:

       applyToEither:有返回值,接收任一任务结果并转换。

       acceptEither:无返回值,消费任一任务结果。

       runAfterEither:无返回值,任一任务完成后执行。

       实战应用

       - API网关:用于并行聚合接口返回,耗时以最慢接口为准。

       与其他方法的区别

       - whenComplete和handle:前者类似finally,无论是否异常都执行,后者允许返回结果。

       - thenApply与thenCompose:前者处理已完成Future的结果,后者计算并返回另一个Future。

       - Async的区别:无Async在特定线程执行,有Async在ForkJoinPool.commonPool()中异步执行。

       以上是CompletableFuture的基本介绍和常见操作,它在并发编程中提供高效且灵活的解决方案。

再谈CompletableFuture之循环创建并发线程

       å‰è¨€

       åœ¨ä¹‹å‰ä¸€ç¯‡æ–‡ç« ã€Šåˆ©ç”¨CompletableFuture做多线程并发操作》里,介绍了如何使用CompletableFuture进行多线程并发操作,但是限定了并发的子线程个数为一个确定值,在代码层面就固定了。当并发的子线程数量不固定时,那么,之前的用法就无法继续使用,此时需要换一个用法。

循环创建并发线程基本思路

       åŸºæœ¬æ€è·¯æ˜¯ï¼šå°†æ‰€æœ‰çš„子线程任务通过循环的方式放入到一个List<CompletableFuture>里,根据业务的场景,选择不同的方法:

       æ‰€æœ‰å­çº¿ç¨‹éƒ½éœ€è¦å®ŒæˆåŽå†æ‰§è¡Œä¸»çº¿ç¨‹

       CompletableFuture.allOf().join()

       å…¶ä¸­ä»»ä½•ä¸€ä¸ªå­çº¿ç¨‹å®ŒæˆåŽå°±æ‰§è¡Œä¸»çº¿ç¨‹

       ComPletableFuture.anyOf()

上代码

       ä¸šåŠ¡åœºæ™¯ï¼šæ ¹æ®ä¸Šä¼ çš„多个行政区编码(adCode)并发查询天气信息。

       å› ä¸ºqWeatherByCode()方法有返回值,所以需要使用CompletableFuture.supplyAsync()方法。

       è¯¥æ–¹æ³•è¿”回一个CompletableFuture对象,然后加入到List<CompletableFuture>对象里。

       ç„¶åŽä½¿ç”¨CompletableFuture.allOf().join()方法,当调用该方法时,主线程会一直阻塞,直到List<CompletableFuture>里的子线程均已完成(或者超时)。

List<CompletableFuture>futures=newArrayList();for(StringadCode:adCodeList){ futures.add(CompletableFuture.supplyAsync(()->qWeatherByCode(adCode)));}CompletableFuture.allOf(futures.toArray(newCompletableFuture[futures.size()])).join();

       éœ€è¦æ³¨æ„çš„是,上面的代码里CompletableFuture.supplyAsync(()->qWeatherByCode(adCode)),没有指定Executor,所以使用默认的线程池ForkJoinPool.commonPool()。

       ForkJoinPool.commonPool()是一个共享线程池(基于服务器内核的限制,如果CPU是八核,每次线程只能起八个,不能自定义线程池),如果使用不当,会对性能造成严重的影响。所以一般建议这里使用自定义的Executor:

List<CompletableFuture>futures=newArrayList();for(StringadCode:adCodeList){ futures.add(CompletableFuture.supplyAsync(()->qWeatherByCode(adCode),asyncExecutor()));}CompletableFuture.allOf(futures.toArray(newCompletableFuture[futures.size()])).join();

       asyncExecutor():

@Bean("asyncExcutor")publicExecutorasyncExecutor(){ log.info("startasyncexecutor");ThreadPoolTaskExecutorthreadPoolTaskExecutor=newThreadPoolTaskExecutor();//配置核心线程数threadPoolTaskExecutor.setCorePoolSize(ThreadPoolConstant.CORE_POOL_SIZE);//配置最大线程数threadPoolTaskExecutor.setMaxPoolSize(ThreadPoolConstant.MAX_POOL_SIZE);//配置队列大小threadPoolTaskExecutor.setQueueCapacity(ThreadPoolConstant.QUEUE_CAPACITY);//配置线程池中线程的名称前缀threadPoolTaskExecutor.setThreadNamePrefix(ThreadPoolConstant.THREAD_NAME_PREFIX);//HelloWorldServiceImplrejection-policy:当pool已经达到maxsize时,如何处理新任务://CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行;//AbortPolicy:拒绝执行新任务,并抛出RejectedExecutionException异常;//DiscardPolicy:丢弃当前将要加入队列的任务;//DiscardOldestPolicy:丢弃任务队列中最旧的任务;threadPoolTaskExecutor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());threadPoolTaskExecutor.initialize();returnthreadPoolTaskExecutor;}CompletableFuture的常用场景packagecom.example.demo;importorg.junit.Test;importjava.util.Arrays;importjava.util.List;importjava.util.Random;importjava.util.concurrent.*;/***Project<demo-project>*Createdbyjorgezhongon/9/:.*/publicclassCompletableFutureDemo{ /***创建CompletableFuture*-runAsync*-supplyAsync*-completedFuture*<p>*异步计算启用的线程池是守护线程*/@Testpublicvoidtest1(){ //1、异步计算:无返回值//默认线程池为:ForkJoinPool.commonPool()CompletableFuture.runAsync(()->{ //TODO:/9/8无返回异步计算System.out.println(Thread.currentThread().isDaemon());});//指定线程池,(到了jdk9CompletableFuture还拓展了延迟的线程池)CompletableFuture.runAsync(()->{ //TODO:/9/8无返回异步计算},Executors.newFixedThreadPool(2));//2、异步计算:有返回值//使用默认线程池CompletableFuture<String>future1=CompletableFuture.supplyAsync(()->"result1");//getNow指定异步计算抛出异常或结果返回null时替代的的值Stringresult1=future1.getNow(null);//指定线程池CompletableFuture<String>future2=CompletableFuture.supplyAsync(()->"result2",Executors.newFixedThreadPool(2));//getNow指定异步计算抛出异常或结果返回null时替代的的值Stringresult2=future2.getNow(null);//3、初始化一个有结果无计算的CompletableFutureCompletableFuture<String>future=CompletableFuture.completedFuture("result");Stringnow=future.getNow(null);System.out.println("now="+now);}/***计算完成时需要对异常进行处理或者对结果进行处理*-whenComplete:同步处理包括异常*-thenApply:同步处理正常结果(前提是没有异常)*<p>*-whenCompleteAsync:异步处理包括异常*-thenApplyAsync:异步处理正常结果(前提是没有异常)*<p>*-exceptionally:处理异常*/@Testpublicvoidtest2(){ CompletableFuture<String>future=CompletableFuture.supplyAsync(()->"result");//whenComplete方法收future的结果和异常,可灵活进行处理//1、同步处理//无返回值:可处理异常future.whenComplete((result,throwable)->System.out.println("result="+result));//有返回值:没有异常处理(前提)CompletableFuture<String>resultFuture1=future.thenApply(result->"result");Stringresult1=resultFuture1.getNow(null);//2、异步处理://无返回值:默认线程池future.whenCompleteAsync((result,throwable)->System.out.println("result="+result));//无返回值:指定线程池future.whenCompleteAsync((result,throwable)->System.out.println("result="+result),Executors.newFixedThreadPool(2));//有返回值:默认线程池CompletableFuture<String>resultFuture2=future.thenApplyAsync(result->"result");Stringresult2=resultFuture2.getNow(null);//有返回值:指定线程池CompletableFuture<String>resultFuture3=future.thenApplyAsync(result->"result",Executors.newFixedThreadPool(2));Stringresult3=resultFuture3.getNow(null);//3、处理异常,处理完之后返回一个结果CompletableFuture<String>exceptionallyFuture=future.whenCompleteAsync((result,throwable)->System.out.println("result="+1/0)).exceptionally(throwable->"发生异常了:"+throwable.getMessage());System.out.println(exceptionallyFuture.getNow(null));}/***异常处理还可以使用以下两个方法*-handle*-handleAsync*<p>*备注:exceptionally同步和异步计算一起用如果出现异常会把异常抛出。用以上的方法可以拦截处理*/@Testpublicvoidtest3(){ CompletableFuture<String>exceptionoHandle=CompletableFuture.completedFuture("producemsg").thenApplyAsync(s->"result"+1/0);StringhandleResult1=exceptionoHandle.handle((s,throwable)->{ if(throwable!=null){ returnthrowable.getMessage();}returns;}).getNow(null);//指定线程池StringhandleResult2=exceptionoHandle.handleAsync((s,throwable)->{ if(throwable!=null){ returnthrowable.getMessage();}returns;},Executors.newFixedThreadPool(2)).getNow(null);}/***生产--消费*-thenAccept:同步的*-thenAcceptAsync:异步的*<p>*接受上一个处理结果,并实现一个Consumer,消费结果*/@Testpublicvoidtest4(){ //同步的CompletableFuture.completedFuture("producemsg").thenAccept(s->System.out.println("syncconsumedmsg:"+s));//异步的//默认线程池CompletableFuture.completedFuture("producemsg").thenAcceptAsync(s->System.out.println("asyncconsumedmsg:"+s));//指定线程池CompletableFuture.completedFuture("producemsg").thenAcceptAsync(s->System.out.println("asyncconsumedmsg:"+s),Executors.newFixedThreadPool(2));}/***取消任务*-cancel*/@Testpublicvoidtest5()throwsInterruptedException{ CompletableFuture<String>message=CompletableFuture.completedFuture("message").thenApplyAsync(s->{ try{ Thread.sleep();}catch(InterruptedExceptione){ e.printStackTrace();}returns+"result";});Stringnow=message.getNow(null);System.out.println("now="+now);//取消booleancancel=message.cancel(true);System.out.println("cancel="+cancel);//如果这里再去获取,会抛出异常,说明已经取消了//Stringnow1=message.getNow(null);Thread.sleep();}/***两个异步计算*-applyToEither:有返回值,同步*-acceptEither:无返回值,同步*-applyToEitherAsync:有返回值,异步*-*/@Testpublicvoidtest6(){ CompletableFuture<String>task1=CompletableFuture.completedFuture("task1").thenApply(s->"task1的计算结果:s1="+s);//同步,有返回值//applyToEither第二个参数接收的值是task1计算的返回值CompletableFuture<String>result1=task1.applyToEither(CompletableFuture.completedFuture("task2").thenApply(s->"task2的计算结果:s2="+s),s->s);System.out.println("task2:"+result1.getNow(null));//同步,无返回值task1.acceptEither(CompletableFuture.completedFuture("task3").thenApply(s->"task3的计算结果:s3="+s),s->System.out.println("task3:"+s));//异步有返回值,默认线程池,也可以指定CompletableFuture<String>result2=task1.applyToEitherAsync(CompletableFuture.completedFuture("task4").thenApply(s->"task4的计算结果:s4="+s),s->s);//由于是异步的,主线程跑的快一点,因此join()之后才能看到跑完的结果System.out.println("task4:"+result2.join());//异步无返回值,指定线程池,也可以使用默认线程池CompletableFuture<Void>task5=task1.acceptEitherAsync(CompletableFuture.completedFuture("task5").thenApply(s->"task5的计算结果:s5="+s),s->System.out.println("task5:"+s),Executors.newFixedThreadPool(2));task5.join();}/***组合计算结果*-runAfterBoth:都计算完之后执行一段代码*-thenAcceptBoth:都计算完之后把结果传入,并执行一段代码*<p>*-thenCombine:组合两个结果*-thenCompose:组合两个结果*/@Testpublicvoidtest7(){ //runAfterBoth方式StringBuildermsg=newStringBuilder("jorgeZhong");CompletableFuture.completedFuture(msg).thenApply(s->s.append("task1,")).runAfterBoth(CompletableFuture.completedFuture(msg).thenApply(s->s.append("task2")),()->System.out.println(msg));//thenAcceptBoth方式CompletableFuture.completedFuture("jorgeZhong").thenApplyAsync(String::toLowerCase).thenAcceptBoth(CompletableFuture.completedFuture("jorgeZhong").thenApplyAsync(String::toUpperCase),(s,s2)->System.out.println("s1:"+s+",s2:"+s2));//thenCombine方式CompletableFuture<String>result1=CompletableFuture.completedFuture("jorgeZhong").thenApply(String::toLowerCase).thenCombine(CompletableFuture.completedFuture("jorgeZhong").thenApply(String::toUpperCase),(s,s2)->"s1:"+s+",s2:"+s2);System.out.println("result1:"+result1.getNow(null));//异步CompletableFuture<String>result=CompletableFuture.completedFuture("jorgeZhong").thenApply(String::toLowerCase).thenCombineAsync(CompletableFuture.completedFuture("jorgeZhong").thenApplyAsync(String::toUpperCase),(s,s2)->"s1:"+s+",s2:"+s2);System.out.println("result:"+result.join());//thenCompose方式CompletableFuture<String>result2=CompletableFuture.completedFuture("jorgeZhong").thenApply(String::toLowerCase).thenCompose(s->CompletableFuture.completedFuture("jorgeZhong").thenApply(String::toUpperCase).thenApply(s1->"s:"+s+",s1:"+s1));System.out.println("result2:"+result2.getNow(null));//异步CompletableFuture<String>result=CompletableFuture.completedFuture("jorgeZhong").thenApply(String::toLowerCase).thenComposeAsync(s->CompletableFuture.c