Java8里面CompletableFuture异步编程详解

CompletableFuture在异常处理方面的一些常见问题和解决方案,建议牢记! CompletableFuture是Java 8引入的一个类,位于java.util.concurrent包下。它提供了一种方便的方式来进行异步编程,尤其是在处理一系列并发任务时非常有用。CompletableFuture支持链式调用和组合多个异步任务。我们可以通过调用各种方法来注册回调函数,在任务完成时获取结果或处理异常。CompletableFuture提供了强大的功能来处理异步编程中的结果和异常。然而,在处理异常时,我们需要注意一些常见的陷阱。 阅读详情

Java8主要的语言增强的能力有:

(1)lambda表达式

(2)stream式操作

(3)CompletableFuture

其中第三个特性,就是今天我们想要聊的话题,正是因为CompletableFuture的出现,才使得使用Java进行异步编程提供了可能。

什么是CompletableFuture?

CompletableFuture在Java里面被用于异步编程,异步通常意味着非阻塞,可以使得我们的任务单独运行在与主线程分离的其他线程中,并且通过 回调可以在主线程中得到异步任务的执行状态,是否完成,和是否异常等信息。CompletableFuture实现了Future, CompletionStage接口,实现了Future接口就可以兼容现在有线程池框架,而CompletionStage接口才是异步编程的接口抽象,里面定义多种异步方法,通过这两者集合,从而打造出了强大的CompletableFuture类。

Future vs CompletableFuture

Futrue在Java里面,通常用来表示一个异步任务的引用,比如我们将任务提交到线程池里面,然后我们会得到一个Futrue,在Future里面有isDone方法来 判断任务是否处理结束,还有get方法可以一直阻塞直到任务结束然后获取结果,但整体来说这种方式,还是同步的,因为需要客户端不断阻塞等待或者不断轮询才能知道任务是否完成。

Future的主要缺点如下:

(1)不支持手动完成

这个意思指的是,我提交了一个任务,但是执行太慢了,我通过其他路径已经获取到了任务结果,现在没法把这个任务结果,通知到正在执行的线程,所以必须主动取消或者一直等待它执行完成。

(2)不支持进一步的非阻塞调用

这个指的是我们通过Future的get方法会一直阻塞到任务完成,但是我还想在获取任务之后,执行额外的任务,因为Future不支持回调函数,所以无法实现这个功能。

(3)不支持链式调用

这个指的是对于Future的执行结果,我们想继续传到下一个Future处理使用,从而形成一个链式的pipline调用,这在Future中是没法实现的。

(4)不支持多个Future合并

比如我们有10个Future并行执行,我们想在所有的Future运行完毕之后,执行某些函数,是没法通过Future实现的。

(5)不支持异常处理

Future的API没有任何的异常处理的api,所以在异步运行时,如果出了问题是不好定位的。

简单的使用CompletableFuture

1,先看一个最简单的例子

在主线程里面创建一个CompletableFuture,然后主线程调用get方法会阻塞,最后我们在一个子线程中 使其终止。

CompletableFuture<String> completableFuture=new CompletableFuture<String>();
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(getThreadName()+"执行.....");
                    completableFuture.complete("success");//在子线程中完成主线程completableFuture的完成

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread t1=new Thread(runnable);
        t1.start();//启动子线程

        String result=completableFuture.get();//主线程阻塞,等待完成
        System.out.println(getThreadName()+"1x:  "+result);

输出结果:

Thread-0线程=> 执行.....
main线程=> 1x:  success

2,运行一个简单的没有返回值的异步任务

CompletableFuture<Void> future=CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(getThreadName()+"正在执行一个没有返回值的异步任务。");
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        future.get();
        System.out.println(getThreadName()+" 结束。");

输出如下:

ForkJoinPool.commonPool-worker-1线程=> 正在执行一个没有返回值的异步任务。
main线程=>  结束。

从上面我们可以看到CompletableFuture默认运行使用的是ForkJoin的的线程池。当然,你也可以用lambda表达式使得代码更精简。

3,运行一个有返回值的异步任务

CompletableFuture<String> future=CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {

                try {
                    System.out.println(getThreadName()+"正在执行一个有返回值的异步任务。");
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                return "OK";
            }
        });

        String result=future.get();

        System.out.println(getThreadName()+"  结果:"+result);

输出结果:

ForkJoinPool.commonPool-worker-1线程=> 正在执行一个有返回值的异步任务。
main线程=>   结果:OK

当然,上面默认的都是ForkJoinPool我们也可以换成Executor相关的Pool,其api都有支持如下:

static CompletableFuture<Void>  runAsync(Runnable runnable)
static CompletableFuture<Void>  runAsync(Runnable runnable, Executor executor)
static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

高级的使用CompletableFuture

前面提到的几种使用方法是使用异步编程最简单的步骤,CompletableFuture.get()的方法会阻塞直到任务完成,这其实还是同步的概念,这对于一个异步系统是不够的,因为真正的异步是需要支持回调函数,这样以来,我们就可以直接在某个任务干完之后,接着执行回调里面的函数,从而做到真正的异步概念。

在CompletableFuture里面,我们通过thenApply(), thenAccept(),thenRun()方法,来运行一个回调函数。

(1)thenApply()

这个方法,其实用过函数式编程的人非常容易理解,类似于scala和spark的map算子,通过这个方法可以进行多次链式转化并返回最终的加工结果。

看下面一个例子:

public static void asyncCallback() throws ExecutionException, InterruptedException {

        CompletableFuture<String> task=CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                System.out.println(getThreadName()+"supplyAsync");
                return "123";
            }
        });

        CompletableFuture<Integer> result1 = task.thenApply(number->{
            System.out.println(getThreadName()+"thenApply1");
            return Integer.parseInt(number);
        });

        CompletableFuture<Integer> result2 = result1.thenApply(number->{
            System.out.println(getThreadName()+"thenApply2");
            return number*2;
        });

        System.out.println(getThreadName()+" => "+result2.get());

    }

输出结果:

ForkJoinPool.commonPool-worker-1线程=> supplyAsync
main线程=> thenApply1
main线程=> thenApply2
main线程=>  => 246

(2)thenAccept()

这个方法,可以接受Futrue的一个返回值,但是本身不在返回任何值,适合用于多个callback函数的最后一步操作使用。

例子如下:

public static void asyncCallback2() throws ExecutionException, InterruptedException {
        CompletableFuture<String> task=CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                System.out.println(getThreadName()+"supplyAsync");
                return "123";
            }
        });

        CompletableFuture<Integer> chain1 = task.thenApply(number->{
            System.out.println(getThreadName()+"thenApply1");
            return Integer.parseInt(number);
        });

        CompletableFuture<Integer> chain2 = chain1.thenApply(number->{
            System.out.println(getThreadName()+"thenApply2");
            return number*2;
        });

       CompletableFuture<Void> result=chain2.thenAccept(product->{
           System.out.println(getThreadName()+"thenAccept="+product);
       });

        result.get();
        System.out.println(getThreadName()+"end");
    }

结果如下:

ForkJoinPool.commonPool-worker-1线程=> supplyAsync
main线程=> thenApply1
main线程=> thenApply2
main线程=> thenAccept=246
main线程=> end

(3) thenRun()

这个方法与上一个方法类似,一般也用于回调函数最后的执行,但这个方法不接受回调函数的返回值,纯粹就代表执行任务的最后一个步骤:

public  static void asyncCallback3() throws ExecutionException, InterruptedException {
        CompletableFuture.supplyAsync(()->{
            System.out.println(getThreadName()+"supplyAsync: 一阶段任务");
            return null;
        }).thenRun(()->{
            System.out.println(getThreadName()+"thenRun: 收尾任务");
        }).get();
    }

结果:

ForkJoinPool.commonPool-worker-1线程=> supplyAsync: 一阶段任务
main线程=> thenRun: 收尾任务

这里注意,截止到目前,前面的例子代码只会涉及两个线程,一个是主线程一个是ForkJoinPool池的线程,但其实上面的每一步都是支持异步运行的,其api如下:

// thenApply() variants
<U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
<U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
<U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)

我们看下改造后的一个例子:

public  static void asyncCallback4() throws ExecutionException, InterruptedException {

        CompletableFuture<String> ref1=  CompletableFuture.supplyAsync(()->{
            try {
                System.out.println(getThreadName()+"supplyAsync开始执行任务1.... ");
//                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(getThreadName()+"supplyAsync: 任务1");
            return null;
        });

        CompletableFuture<String> ref2= CompletableFuture.supplyAsync(()->{
            try {

            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(getThreadName()+"thenApplyAsync: 任务2");
            return null;
        });

        CompletableFuture<String> ref3=ref2.thenApplyAsync(value->{
            System.out.println(getThreadName()+"thenApplyAsync: 任务2的子任务");
            return  null;
        });
        Thread.sleep(4000);
        System.out.println(getThreadName()+ref3.get());
    }

输出结果如下:

ForkJoinPool.commonPool-worker-1线程=> supplyAsync开始执行任务1.... 
ForkJoinPool.commonPool-worker-1线程=> supplyAsync: 任务1
ForkJoinPool.commonPool-worker-1线程=> supplyAsync: 任务2
ForkJoinPool.commonPool-worker-2线程=> thenApplyAsync: 任务2的子任务
main线程=> null

我们可以看到,ForkJoin池的线程1,执行了前面的三个任务,但是第二个任务的子任务,因为我们了使用也异步提交所以它用的线程是ForkJoin池的线程2,最终由于main线程处执行了get是最后结束的。

还有一点需要注意:

ForkJoinPool所有的工作线程都是守护模式的,也就是说如果主线程退出,那么整个处理任务都会结束,而不管你当前的任务是否执行完。如果需要主线程等待结束,可采用ExecutorsThreadPool,如下:

ExecutorService pool = Executors.newFixedThreadPool(5);
final CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                ... }, pool);

(4)thenCompose合并两个有依赖关系的CompletableFutures的执行结果

CompletableFutures在执行两个依赖的任务合并时,会返回一个嵌套的结果列表,为了避免这种情况我们可以使用thenCompose来返回,直接获取最顶层的结果数据即可:

public static void asyncCompose() throws ExecutionException, InterruptedException {

        CompletableFuture<String>  future1=CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                return "1";
            }
        });

       CompletableFuture<String>nestedResult = future1.thenCompose(value->
               CompletableFuture.supplyAsync(()->{
                return value+"2";
       }));

        System.out.println(nestedResult.get());
    }

(5)thenCombine合并两个没有依赖关系的CompletableFutures任务

CompletableFuture<Double>  d1= CompletableFuture.supplyAsync(new Supplier<Double>() {
            @Override
            public Double get() {
                return 1d;
            }
        });
        CompletableFuture<Double>  d2= CompletableFuture.supplyAsync(new Supplier<Double>() {
            @Override
            public Double get() {
                return 2d;
            }
        });
      CompletableFuture<Double> result=  d1.thenCombine(d2,(number1,number2)->{
            return  number1+number2;
        });

        System.out.println(result.get());

(6)合并多个任务的结果allOf与anyOf

上面说的是两个任务的合并,那么多个任务需要使用allOf或者anyOf方法。

allOf适用于,你有一系列独立的future任务,你想等其所有的任务执行完后做一些事情。举个例子,比如我想下载100个网页,传统的串行,性能肯定不行,这里我们采用异步模式,同时对100个网页进行下载,当所有的任务下载完成之后,我们想判断每个网页是否包含某个关键词。

下面我们通过随机数来模拟上面的这个场景如下:

public static void mutilTaskTest() throws ExecutionException, InterruptedException {
         //添加n个任务
        CompletableFuture<Double> array[]=new CompletableFuture[3];
        for ( int i = 0; i < 3; i++) {
            array[i]=CompletableFuture.supplyAsync(new Supplier<Double>() {
                @Override
                public Double get() {
                    return Math.random();
                }
            });
        }
       //获取结果的方式一
//       CompletableFuture.allOf(array).get();
//        for(CompletableFuture<Double> cf:array){
//            if(cf.get()>0.6){
//                System.out.println(cf.get());
//            }
//        }
        //获取结果的方式二,过滤大于指定数字,在收集输出
       List<Double> rs= Stream.of(array).map(CompletableFuture::join).filter(number->number>0.6).collect(Collectors.toList());
       System.out.println(rs);
    }

结果如下:

[0.8228784717152199]

注意其中的join方法和get方法类似,仅仅在于在Future不能正常完成的时候抛出一个unchecked的exception,这可以确保它用在Stream的map方法中,直接使用get是没法在map里面运行的。

anyOf方法,也比较简单,意思就是只要在多个future里面有一个返回,整个任务就可以结束,而不需要等到每一个future结束。

CompletableFuture<String> f1=CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    TimeUnit.SECONDS.sleep(4);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "wait 4 seconds";
            }
        });
        CompletableFuture<String> f2=CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "wait 2 seconds";
            }
        });

        CompletableFuture<String> f3=CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    TimeUnit.SECONDS.sleep(4);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "wait 10 seconds";
            }
        });

       CompletableFuture<Object> result= CompletableFuture.anyOf(f1,f2,f3);

        System.out.println(result.get());

输出结果:

wait 2 seconds

注意由于Anyof返回的是其中任意一个Future所以这里没有明确的返回类型,统一使用Object接受,留给使用端处理。

(7)exceptionally异常处理

异常处理是异步计算的一个重要环节,下面看看如何在CompletableFuture中使用:

   int age=-1;
       CompletableFuture<String> task= CompletableFuture.supplyAsync(new Supplier<String>() {
           @Override
           public String get() {

               if(age<0){
                   throw new IllegalArgumentException("性别必须大于0");
               }

               if(age<18){
                   return "未成年人";
               }

               return "成年人";
           }
       }).exceptionally(ex->{
           System.out.println(ex.getMessage());
           return "发生 异常"+ex.getMessage();
       });

        System.out.println(task.get());

结果如下:

java.lang.IllegalArgumentException: 性别必须大于0
发生 异常java.lang.IllegalArgumentException: 性别必须大于0

此外还有另外一种异常捕捉方法handle,无论发生异常都会执行,示例如下:

        int age=10;
        CompletableFuture<String> task= CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {

                if(age<0){
                    throw new IllegalArgumentException("性别必须大于0");
                }

                if(age<18){
                    return "未成年人";
                }

                return "成年人";
            }
        }).handle((res,ex)->{
            System.out.println("执行handle");
            if(ex!=null){
                System.out.println("发生异常");
                return "发生 异常"+ex.getMessage();
            }

            return res;
        });

        System.out.println(task.get());

输出结果:

执行handle
发生异常
发生 异常java.lang.IllegalArgumentException: 性别必须大于0

注意上面的方法如果正常执行,也会执行handle方法。

JDK9 CompletableFuture 类增强的主要内容

(1)支持对异步方法的超时调用

orTimeout()
completeOnTimeout()

(2)支持延迟调用

Executor delayedExecutor(long delay, TimeUnit unit, Executor executor)
Executor delayedExecutor(long delay, TimeUnit unit)

详细内容,可以参考Oracle官网文档,这里不再过多介绍。

总结:

本文主要介绍了CompletableFuture的定义,概念及在Java中使用的例子,通过CompletableFuture我们可以实现异步编程的能力,从而使得我们开发的任务可以拥有更强大的能力。

CompletableFuture异常优雅处理方式 CompletableFuture是Java 8提供了新特性,实现了CompletionStage接口和Future接口,增加了异步回调、流式处理、多个Future组合处理的能力。可以帮助我们简化异步编程的复杂性,让我们在Java在处理多任务的协同工作时更加顺畅便利。 阅读详情

相关推荐

java future专题 2-6 CompletableFuture源码探秘-异常处理(1)

todo

xxcupid的博客 988

CompletableFuture详解~runAsync

这个例子创建一个一个异步执行的阶段: static void runAsyncExample() { CompletableFuture cf = CompletableFuture.runAsync(() -> { assertTrue(Thread.currentThread().isDaemon()); randomSleep(); }); assertFalse(cf.isDone()); sleepEnough();

小强快跑~~ 3万+

JAVA并发编程进阶~CompletableFuture异步编程详解

Java8的CompletableFuture是异步编程利器,支持非阻塞任务执行、链式处理、多任务组合和异常捕获。核心特性包括:异步创建任务(supplyAsync/runAsync)、结果转换(thenApply)、任务组合(allOf/anyOf)、异常处理(exceptionally)和超时控制(completeOnTimeout)。典型应用场景如用户注册流程,可串联验证、发邮件、记录日志等异步操作。最佳实践建议:使用自定义线程池、避免阻塞调用、完整处理异常、设置合理超时。CompletableFut

zjw541806的博客 150

使用CompletableFuture.runAsync()来完成异步任务

CompletableFuture 异步编排

m0_46539364的博客 2万+

Autodesk全家桶:从AutoCAD到Maya,设计师必备的7款神器全解析

本文全面解析Autodesk全家桶中的7款设计师必备软件,包括AutoCAD、Revit、Inventor、Fusion 360、Maya和3ds Max等。从二维制图到三维建模,从建筑信息模型(BIM)到影视动画制作,这些工具在工程设计、建筑可视化和数字创意领域展现出强大的协同效应。通过实战案例展示如何整合工作流,显著提升设计效率与项目质量。

weixin_29237635的博客 460

绕开华为通道,获取解锁码解锁BootLoader

刷机有风险,操作需谨慎,如果因为各种因素导致手机变砖无法开机,本教程概不负责,望悉知 前言 这篇文章的大多内容是根据我自己找的一篇文章《绕开华为通道,获取解锁码解锁BootLoader》来编写的,里面的大部分内容是文章的原内容。下面的都是我参考文章中做了一些小部分的修改,增加了我华为P8手机的一些操作,下面开始讲述我的解锁过程。 因为华为官方在2018年的七八月份吧,关闭了解锁码的申请通道,这...

Martin.Mu `s Special Column 5万+

Java 8 的异步编程利器 CompletableFuture 详解

文章目录一个例子回顾 Future一个例子走进CompletableFutureCompletableFuture使用场景创建异步任务supplyAsync方法runAsync方法任务异步回调1. thenRun/thenRunAsync2.thenAccept/thenAcceptAsync3. thenApply/thenApplyAsync4. exceptionally5. whenComplete方法6. handle方法多个任务组合处理AND组合关系OR组合的关系AllOfAnyOfthenCo

ThinkWon的博客 5829

路径规划 | 详解混合A*算法Hybrid A*(附ROS C++/Python/Matlab仿真)

Hybrid A*算法通过结合连续状态空间搜索、运动约束考虑和轨迹优化等技术,弥补了普通A*算法在高维连续空间和的不足,提高了路径规划的效率和鲁棒性,广泛应用于车规级路径规划。本文详细图解Hybrid A*算法的原理——启发式、维诺耗散项、节点扩展法则等,并给出ROS C++、python、matlab三种语言的仿真实现加深理解

FRIGIDWINTER的博客 1万+

Java 8 异步编程进阶:CompletableFuture 详解与最佳实践

/ 使用 supplyAsync 创建一个有返回值的异步任务,并指定自定义线程池// 模拟耗时任务try {// 阻塞等待任务完成并获取结果使用场景:适用于需要对线程池进行精细控制的场景,例如限制线程数量或使用特定的线程池策略。

shitou的博客 1177

petalinux2022.2启动文件编译配置

petalinux2021之前的版本里,导入目录components/yocto/下的“environment-setup-aarch64-xilinx-linux” 和 “layers/core/oe-init-build-env”的环境,能使用Yocto的devtool工具。(加入下面内容,先petalinux-build下载完成后才能有源码)制作 BOOT.BIN 启动文件:petalinux-package --boot --fsbl --fpga --u-boot --force。

wangjie36的博客 1386

医图论文 Arxiv‘24 | 自我先验引导的 Mamba-UNet 网络在医学图像超分辨率中的应用

作者提出了一种自我先验引导的 Mamba-UNet 网络(简称 SMamba-UNet)用于医学图像超分辨率。现有方法主要基于卷积神经网络(CNNs)或 Transformer。基于 CNN 的方法无法捕捉长距离依赖关系,而基于 Transformer 的方法由于其二阶计算复杂度,面临沉重的计算挑战。最近,状态空间模型(SSMs)尤其是 Mamba 出现了,它能够以线性计算复杂度建模长距离依赖。

小白学视觉 261

Java8 异步编程利器 CompletableFuture 详解(全网看这一篇就行)

我们知道Future的有局限性,它没法直接对多个任务进行链式、组合等处理,需要借助并发工具类才能完成,实现逻辑比较复杂。而是对Future的扩展和增强。实现了Future接口,并在此基础上进行了丰富的扩展,完美弥补了Future的局限性,同时实现了对任务编排的能力。借助这项能力,可以轻松地组织不同任务的运行顺序、规则以及方式。从某种程度上说,这项能力是它的核心能力。而在以往,虽然通过等工具类也可以实现任务的编排,但需要复杂的逻辑处理,不仅耗费精力且难以维护。

m0_72885838的博客 3298

Python爬虫实战:使用最新技术爬取GitHub Trending项目

本文将详细介绍如何使用Python最新技术栈构建一个高效的GitHub Trending爬虫。我们将使用异步请求库httpx、HTML解析库parsel、数据存储方案以及反反爬技术,完整实现一个能够稳定获取GitHub Trending数据的爬虫系统。文章包含5000余字详细教程,从环境搭建到代码实现,再到数据处理和存储,最后部署运行,提供全方位指导。GitHub Trending页面展示了GitHub上当前最受欢迎的项目,对于开发者了解技术趋势、发现优秀项目非常有价值。

2201_76125261的博客 735

详解Java8中新引入的异步编程API之CompletableFuture

java8中引入了不少新的特性,使用最多的还是要数lambda、Stream API和CompletableFuture了吧?这里重点对CompletableFutre做一个比较深入、全面的了解。

github_38727595的博客 1089

Claude Code 里的 MCP 连接失败到底在报什么

文档还说明,HTTP 类型、stdio 类型等 MCP server 的接入方式不同,stdio server 会被 Claude Code 当作本地进程拉起,而 HTTP server 则需要 Claude Code 去访问一个已经存在的 HTTP endpoint。把这段输出翻成更接地气的运维语言,就是 Claude Code 已经知道我们想接两个外部能力,一个是 SAP ADT 官方 MCP,一个是 Chrome DevTools MCP,但当前没有一个完成握手。,因为它的信号更明确。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 142

2024年下半年网络规划设计师论文真题

3、深入论述自身参与的工业网络是如何实施的,为实现制造业的智能化,如何实现数据的跨系统互通,促进各种工业数据的充分流动和无缝集成以及数据安全。3、结合自身参与的网络建设,详细叙述针对该网络“去NAT”的规划和设计方案。4、在实施过程中遇到的问题以及如何处理,项目实施后的效果和评价。2、大型园区网络“去NAT”改造和业务融合的整体架构。1、“网络去NAT”对推进ipv6演进和应用的意义。4、改造过程中遇到的问题及解决方案。2、简要叙述自身参与的制造网络建设。1、网络规划在智能制造中的意义。

鹿鸣天涯 2364

多线程异步编程之Java8 CompletableFuture详解(保姆级教程)

文章目录背景类结构学习使用创建异步任务`supplyAsync``runAsync`异步回调`thenApply``thenAccept``thenRun``exceptionally``whenComplete``handle`联合处理双CompletableFuture联合处理`thenCombine``thenAcceptBoth``runAfterBoth``applyToEither``acceptEither``runAfterEither``thenCompose`多CompletableFu

念念不忘,必有回响 6745

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Java8 异步编程利器 CompletableFuture 详解

我们知道Future的有局限性,它没法直接对多个任务进行链式、组合等处理,需要借助并发工具类才能完成,实现逻辑比较复杂。而是对Future的扩展和增强。实现了Future接口,并在此基础上进行了丰富的扩展,完美弥补了Future的局限性,同时实现了对任务编排的能力。借助这项能力,可以轻松地组织不同任务的运行顺序、规则以及方式。从某种程度上说,这项能力是它的核心能力。而在以往,虽然通过等工具类也可以实现任务的编排,但需要复杂的逻辑处理,不仅耗费精力且难以维护。...

EndTheme_Xin的博客 573

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

java并发设计模式:Future与JDK8的CompletableFuture异步编程详解

一. Future JDK 5引入了Future模式。Future接口是Java多线程Future模式的实现,在java.util.concurrent包中,可以来进行异步计算。 Future模式是多线程设计常用的一种设计模式。Future模式可以理解成:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时间之后,我就便可以从Future那...

Phantom丶LF的专栏 2147

Java8新的异步编程方式 CompletableFuture(一)

一. Future JDK 5引入了Future模式。Future接口是Java多线程Future模式的实现,在java.util.concurrent包中,可以来进行异步计算。 Future模式是多线程设计常用的一种设计模式。Future模式可以理解成:我有一个任务,提交给了Future...

207

Java CompletableFuture异步编程完全指南:从Future升级到响应式编排

本文将系统讲解Java 8引入的CompletableFuture,从传统Future的局限性入手,深入剖析其核心原理、丰富的API用法以及典型应用场景,帮助你掌握异步编程的现代范式。:假设你需要调用三个不同的远程服务,然后将结果合并返回。:不关心上一步的结果,只在前序步骤完成后执行一个动作。:当一个异步任务依赖另一个异步任务的结果时使用,避免。:当两个互不依赖的异步任务都完成后,合并它们的结果。:接收上一步的结果,进行转换,返回新值。如果已经知道结果,可以创建已完成状态的。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 406

Java8异步编程-CompletableFuture

异步编程的难点 如何优雅地实现异步编程一直都是一个难题,异步编程的通常做法就是采用callback的方法,但是这种方法通常会把代码嵌套在正常流程的代码中,而且当有多层嵌套的时候代码更加难以维护。 另外还有一点,异步编程的异常处理也是难以未维护,特别是在Java中,异步编程通常由新的线程完成,而子线程的异常是无法在父线程捕获的,那么对于异步执行结果的获取就需要付出更大的代价,比如通过:轮询、事件驱动等来完成。 从Future说起 Java5之后就引入Future用于异步编程,通过get()方法来对异步执行结果

m0_57983661的博客 1001

深入理解 CompletableFuture

提供了回调机制:CompletableFuture 提供了回调功能,我们可以注册回调函数来处理任务完成时的结果,而不必阻塞线程等待任务完成。这样可以提高并发性能,减少线程的阻塞时间。提供了异常处理:CompletableFutur 具备丰富的异常处理机制,可以捕获任务执行中的异常,并允许我们定义自定义的异常处理策略。能够取消任务:我们可以使用cancel()取消任务的执行,同时还可以指定是否中断正在执行的任务。这提供了更好的任务控制能力。强大的异步编程能力。

m0_56563273的博客 2132
上一篇: Redis 到底是单线程还是多线程?我要吊打面试官!
下一篇: java安全管理器SecurityManager介绍
shadow_zed
博客等级 码龄10年 6289粉丝 68原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值