Java8 CompletableFuture异步非阻塞做法

article/2025/10/28 7:23:43
  • 创建异步任务

    • Future.submit

    • supplyAsync / runAsync

  • 异步回调

    • thenApply / thenApplyAsync

    • thenAccept / thenRun

    • exceptionally

    • whenComplete

    • handle

  • 组合处理

    • thenCombine / thenAcceptBoth / runAfterBoth

    • applyToEither / acceptEither / runAfterEither

    • thenCompose

    • allOf / anyOf


CompletableFuture实现了CompletionStage接口和Future接口,前者是对后者的一个扩展,增加了异步回调、流式处理、多个Future组合处理的能力,使Java在处理多任务的协同工作时更加顺畅便利。

一、创建异步任务

1、Future.submit

通常的线程池接口类ExecutorService,其中execute方法的返回值是void,即无法获取异步任务的执行状态,3个重载的submit方法的返回值是Future,可以据此获取任务执行的状态和结果,示例如下:

    @Testpublic void test1() throws Exception {// 创建异步执行任务:ExecutorService executorService= Executors.newSingleThreadExecutor();Future<Double> cf = executorService.submit(()->{System.out.println(Thread.currentThread()+" start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}if(false){throw new RuntimeException("test");}else{System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());return 1.2;}});System.out.println("main thread start,time->"+System.currentTimeMillis());//等待子任务执行完成,如果已完成则直接返回结果//如果执行任务异常,则get方法会把之前捕获的异常重新抛出System.out.println("run result->"+cf.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

执行结果如下: 

 

子线程是异步执行的,主线程休眠等待子线程执行完成,子线程执行完成后唤醒主线程,主线程获取任务执行结果后退出。

很多博客说使用不带等待时间限制的get方法时,如果子线程执行异常了会导致主线程长期阻塞,这其实是错误的,子线程执行异常时其异常会被捕获,然后修改任务的状态为异常结束并唤醒等待的主线程,get方法判断任务状态发生变更,就终止等待了,并抛出异常。将上述用例中if(false)改成if(true) ,执行结果如下:

 

get方法抛出异常导致主线程异常终止。

2、supplyAsync / runAsync

supplyAsync表示创建带返回值的异步任务的,相当于ExecutorService submit(Callable<T> task) 方法,runAsync表示创建无返回值的异步任务,相当于ExecutorService submit(Runnable task)方法,这两方法的效果跟submit是一样的,测试用例如下:

    @Testpublic void test2() throws Exception {// 创建异步执行任务,有返回值CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}if(true){throw new RuntimeException("test");}else{System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());return 1.2;}});System.out.println("main thread start,time->"+System.currentTimeMillis());//等待子任务执行完成System.out.println("run result->"+cf.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}@Testpublic void test3() throws Exception {// 创建异步执行任务,无返回值CompletableFuture cf = CompletableFuture.runAsync(()->{System.out.println(Thread.currentThread()+" start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}if(false){throw new RuntimeException("test");}else{System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());}});System.out.println("main thread start,time->"+System.currentTimeMillis());//等待子任务执行完成System.out.println("run result->"+cf.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

这两方法各有一个重载版本,可以指定执行异步任务的Executor实现,如果不指定,默认使用ForkJoinPool.commonPool(),如果机器是单核的,则默认使用ThreadPerTaskExecutor,该类是一个内部类,每次执行execute都会创建一个新线程。测试用例如下:

    @Testpublic void test4() throws Exception {ForkJoinPool pool=new ForkJoinPool();// 创建异步执行任务:CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}if(true){throw new RuntimeException("test");}else{System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());return 1.2;}},pool);System.out.println("main thread start,time->"+System.currentTimeMillis());//等待子任务执行完成System.out.println("run result->"+cf.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}@Testpublic void test5() throws Exception {ExecutorService executorService= Executors.newSingleThreadExecutor();// 创建异步执行任务:CompletableFuture cf = CompletableFuture.runAsync(()->{System.out.println(Thread.currentThread()+" start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}if(false){throw new RuntimeException("test");}else{System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());}},executorService);System.out.println("main thread start,time->"+System.currentTimeMillis());//等待子任务执行完成System.out.println("run result->"+cf.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

二、异步回调

1、thenApply / thenApplyAsync

thenApply 表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,测试用例如下:

    @Testpublic void test6() throws Exception {ForkJoinPool pool=new ForkJoinPool();// 创建异步执行任务:CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start job1,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job1,time->"+System.currentTimeMillis());return 1.2;},pool);//cf关联的异步任务的返回值作为方法入参,传入到thenApply的方法中//thenApply这里实际创建了一个新的CompletableFuture实例CompletableFuture<String> cf2=cf.thenApply((result)->{System.out.println(Thread.currentThread()+" start job2,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job2,time->"+System.currentTimeMillis());return "test:"+result;});System.out.println("main thread start cf.get(),time->"+System.currentTimeMillis());//等待子任务执行完成System.out.println("run result->"+cf.get());System.out.println("main thread start cf2.get(),time->"+System.currentTimeMillis());System.out.println("run result->"+cf2.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

其执行结果如下:

 

job1执行结束后,将job1的方法返回值作为入参传递到job2中并立即执行job2。

thenApplyAsync与thenApply的区别在于,前者是将job2提交到线程池中异步执行,实际执行job2的线程可能是另外一个线程,后者是由执行job1的线程立即执行job2,即两个job都是同一个线程执行的。将上述测试用例中thenApply改成thenApplyAsync后,执行结果如下:

 

从输出可知,执行job1和job2是两个不同的线程。thenApplyAsync有一个重载版本,可以指定执行异步任务的Executor实现,如果不指定,默认使用ForkJoinPool.commonPool()

下述的多个方法,每个方法都有两个以Async结尾的方法,一个使用默认的Executor实现,一个使用指定的Executor实现,不带Async的方法是由触发该任务的线程执行该任务,带Async的方法是由触发该任务的线程将任务提交到线程池,执行任务的线程跟触发任务的线程不一定是同一个。

2、thenAccept / thenRun

thenAccept 同 thenApply 接收上一个任务的返回值作为参数,但是无返回值;thenRun 的方法没有入参,也买有返回值,测试用例如下:

    @Testpublic void test7() throws Exception {ForkJoinPool pool=new ForkJoinPool();// 创建异步执行任务:CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start job1,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job1,time->"+System.currentTimeMillis());return 1.2;},pool);//cf关联的异步任务的返回值作为方法入参,传入到thenApply的方法中CompletableFuture cf2=cf.thenApply((result)->{System.out.println(Thread.currentThread()+" start job2,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job2,time->"+System.currentTimeMillis());return "test:"+result;}).thenAccept((result)-> { //接收上一个任务的执行结果作为入参,但是没有返回值System.out.println(Thread.currentThread()+" start job3,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(result);System.out.println(Thread.currentThread()+" exit job3,time->"+System.currentTimeMillis());}).thenRun(()->{ //无入参,也没有返回值System.out.println(Thread.currentThread()+" start job4,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println("thenRun do something");System.out.println(Thread.currentThread()+" exit job4,time->"+System.currentTimeMillis());});System.out.println("main thread start cf.get(),time->"+System.currentTimeMillis());//等待子任务执行完成System.out.println("run result->"+cf.get());System.out.println("main thread start cf2.get(),time->"+System.currentTimeMillis());//cf2 等待最后一个thenRun执行完成System.out.println("run result->"+cf2.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

其执行结果如下:

 

3、 exceptionally

exceptionally方法指定某个任务执行异常时执行的回调方法,会将抛出异常作为参数传递到回调方法中,如果该任务正常执行则会exceptionally方法返回的CompletionStage的result就是该任务正常执行的结果,测试用例如下:

    @Testpublic void test8() throws Exception {ForkJoinPool pool=new ForkJoinPool();// 创建异步执行任务:CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+"job1 start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}if(true){throw new RuntimeException("test");}else{System.out.println(Thread.currentThread()+"job1 exit,time->"+System.currentTimeMillis());return 1.2;}},pool);//cf执行异常时,将抛出的异常作为入参传递给回调方法CompletableFuture<Double> cf2= cf.exceptionally((param)->{System.out.println(Thread.currentThread()+" start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println("error stack trace->");param.printStackTrace();System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());return -1.1;});//cf正常执行时执行的逻辑,如果执行异常则不调用此逻辑CompletableFuture cf3=cf.thenAccept((param)->{System.out.println(Thread.currentThread()+"job2 start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println("param->"+param);System.out.println(Thread.currentThread()+"job2 exit,time->"+System.currentTimeMillis());});System.out.println("main thread start,time->"+System.currentTimeMillis());//等待子任务执行完成,此处无论是job2和job3都可以实现job2退出,主线程才退出,如果是cf,则主线程不会等待job2执行完成自动退出了//cf2.get时,没有异常,但是依然有返回值,就是cf的返回值System.out.println("run result->"+cf2.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

其输出如下:

 抛出异常后,只有cf2执行了,cf3没有执行。将上述示例中的if(true) 改成if(false),其输出如下:

 

cf2没有指定,其result就是cf执行的结果,理论上cf2.get应该立即返回的,此处是等待了cf3,即job2执行完成后才返回,具体原因且待下篇源码分析时再做探讨。

4、whenComplete

whenComplete是当某个任务执行完成后执行的回调方法,会将执行结果或者执行期间抛出的异常传递给回调方法,如果是正常执行则异常为null,回调方法对应的CompletableFuture的result和该任务一致,如果该任务正常执行,则get方法返回执行结果,如果是执行异常,则get方法抛出异常。测试用例如下:

    @Testpublic void test9() throws Exception {// 创建异步执行任务:CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+"job1 start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}if(false){throw new RuntimeException("test");}else{System.out.println(Thread.currentThread()+"job1 exit,time->"+System.currentTimeMillis());return 1.2;}});//cf执行完成后会将执行结果和执行过程中抛出的异常传入回调方法,如果是正常执行的则传入的异常为nullCompletableFuture<Double> cf2=cf.whenComplete((a,b)->{System.out.println(Thread.currentThread()+"job2 start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}if(b!=null){System.out.println("error stack trace->");b.printStackTrace();}else{System.out.println("run succ,result->"+a);}System.out.println(Thread.currentThread()+"job2 exit,time->"+System.currentTimeMillis());});//等待子任务执行完成System.out.println("main thread start wait,time->"+System.currentTimeMillis());//如果cf是正常执行的,cf2.get的结果就是cf执行的结果//如果cf是执行异常,则cf2.get会抛出异常System.out.println("run result->"+cf2.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

执行结果如下:

 将上述示例中的if(false) 改成if(true),其输出如下:

5、handle

跟whenComplete基本一致,区别在于handle的回调方法有返回值,且handle方法返回的CompletableFuture的result是回调方法的执行结果或者回调方法执行期间抛出的异常,与原始CompletableFuture的result无关了。测试用例如下:

    @Testpublic void test10() throws Exception {// 创建异步执行任务:CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+"job1 start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}if(true){throw new RuntimeException("test");}else{System.out.println(Thread.currentThread()+"job1 exit,time->"+System.currentTimeMillis());return 1.2;}});//cf执行完成后会将执行结果和执行过程中抛出的异常传入回调方法,如果是正常执行的则传入的异常为nullCompletableFuture<String> cf2=cf.handle((a,b)->{System.out.println(Thread.currentThread()+"job2 start,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}if(b!=null){System.out.println("error stack trace->");b.printStackTrace();}else{System.out.println("run succ,result->"+a);}System.out.println(Thread.currentThread()+"job2 exit,time->"+System.currentTimeMillis());if(b!=null){return "run error";}else{return "run succ";}});//等待子任务执行完成System.out.println("main thread start wait,time->"+System.currentTimeMillis());//get的结果是cf2的返回值,跟cf没关系了System.out.println("run result->"+cf2.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

 其执行结果如下:

将上述示例中的if(true) 改成if(false),其输出如下:

 

三、组合处理

1、thenCombine / thenAcceptBoth / runAfterBoth

这三个方法都是将两个CompletableFuture组合起来,只有这两个都正常执行完了才会执行某个任务,区别在于,thenCombine会将两个任务的执行结果作为方法入参传递到指定方法中,且该方法有返回值;

thenAcceptBoth同样将两个任务的执行结果作为方法入参,但是无返回值;runAfterBoth没有入参,也没有返回值。注意两个任务中只要有一个执行异常,则将该异常信息作为指定任务的执行结果。测试用例如下:

    @Testpublic void test11() throws Exception {ForkJoinPool pool=new ForkJoinPool();// 创建异步执行任务:CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start job1,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job1,time->"+System.currentTimeMillis());return 1.2;});CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start job2,time->"+System.currentTimeMillis());try {Thread.sleep(1500);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job2,time->"+System.currentTimeMillis());return 3.2;});//cf和cf2的异步任务都执行完成后,会将其执行结果作为方法入参传递给cf3,且有返回值CompletableFuture<Double> cf3=cf.thenCombine(cf2,(a,b)->{System.out.println(Thread.currentThread()+" start job3,time->"+System.currentTimeMillis());System.out.println("job3 param a->"+a+",b->"+b);try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job3,time->"+System.currentTimeMillis());return a+b;});//cf和cf2的异步任务都执行完成后,会将其执行结果作为方法入参传递给cf3,无返回值CompletableFuture cf4=cf.thenAcceptBoth(cf2,(a,b)->{System.out.println(Thread.currentThread()+" start job4,time->"+System.currentTimeMillis());System.out.println("job4 param a->"+a+",b->"+b);try {Thread.sleep(1500);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job4,time->"+System.currentTimeMillis());});//cf4和cf3都执行完成后,执行cf5,无入参,无返回值CompletableFuture cf5=cf4.runAfterBoth(cf3,()->{System.out.println(Thread.currentThread()+" start job5,time->"+System.currentTimeMillis());try {Thread.sleep(1000);} catch (InterruptedException e) {}System.out.println("cf5 do something");System.out.println(Thread.currentThread()+" exit job5,time->"+System.currentTimeMillis());});System.out.println("main thread start cf.get(),time->"+System.currentTimeMillis());//等待子任务执行完成System.out.println("cf run result->"+cf.get());System.out.println("main thread start cf5.get(),time->"+System.currentTimeMillis());System.out.println("cf5 run result->"+cf5.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

其运行结果如下:

 

job1 和 job2几乎同时运行,job2比job1先执行完成,等job1退出后,job3和job4几乎同时开始运行,job4先退出,等job3执行完成,job5开始了,等job5执行完成后,主线程退出。

2、applyToEither / acceptEither / runAfterEither

这三个方法都是将两个CompletableFuture组合起来,只要其中一个执行完了就会执行某个任务,其区别在于applyToEither会将已经执行完成的任务的执行结果作为方法入参,并有返回值;

acceptEither同样将已经执行完成的任务的执行结果作为方法入参,但是没有返回值;runAfterEither没有方法入参,也没有返回值。注意两个任务中只要有一个执行异常,则将该异常信息作为指定任务的执行结果。测试用例如下:

    @Testpublic void test12() throws Exception {// 创建异步执行任务:CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start job1,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job1,time->"+System.currentTimeMillis());return 1.2;});CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start job2,time->"+System.currentTimeMillis());try {Thread.sleep(1500);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job2,time->"+System.currentTimeMillis());return 3.2;});//cf和cf2的异步任务都执行完成后,会将其执行结果作为方法入参传递给cf3,且有返回值CompletableFuture<Double> cf3=cf.applyToEither(cf2,(result)->{System.out.println(Thread.currentThread()+" start job3,time->"+System.currentTimeMillis());System.out.println("job3 param result->"+result);try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job3,time->"+System.currentTimeMillis());return result;});//cf和cf2的异步任务都执行完成后,会将其执行结果作为方法入参传递给cf3,无返回值CompletableFuture cf4=cf.acceptEither(cf2,(result)->{System.out.println(Thread.currentThread()+" start job4,time->"+System.currentTimeMillis());System.out.println("job4 param result->"+result);try {Thread.sleep(1500);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job4,time->"+System.currentTimeMillis());});//cf4和cf3都执行完成后,执行cf5,无入参,无返回值CompletableFuture cf5=cf4.runAfterEither(cf3,()->{System.out.println(Thread.currentThread()+" start job5,time->"+System.currentTimeMillis());try {Thread.sleep(1000);} catch (InterruptedException e) {}System.out.println("cf5 do something");System.out.println(Thread.currentThread()+" exit job5,time->"+System.currentTimeMillis());});System.out.println("main thread start cf.get(),time->"+System.currentTimeMillis());//等待子任务执行完成System.out.println("cf run result->"+cf.get());System.out.println("main thread start cf5.get(),time->"+System.currentTimeMillis());System.out.println("cf5 run result->"+cf5.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

其运行结果如下:

 

job1 和job2 同时开始运行,job2先执行完成,然后job4开始执行,理论上job3和job4应该同时开始运行,但是此时只有job4开始执行了,job3是等待job1执行完成后才开始执行,job4先于job3执行完成,然后job5开始执行,等job5执行完成后,主线程退出。上述差异且到下篇源码分析时再做探讨。

3、thenCompose

thenCompose方法会在某个任务执行完成后,将该任务的执行结果作为方法入参然后执行指定的方法,该方法会返回一个新的CompletableFuture实例,如果该CompletableFuture实例的result不为null,则返回一个基于该result的新的CompletableFuture实例;如果该CompletableFuture实例为null,则,然后执行这个新任务,测试用例如下:

    @Testpublic void test13() throws Exception {// 创建异步执行任务:CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start job1,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job1,time->"+System.currentTimeMillis());return 1.2;});CompletableFuture<String> cf2= cf.thenCompose((param)->{System.out.println(Thread.currentThread()+" start job2,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job2,time->"+System.currentTimeMillis());return CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start job3,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job3,time->"+System.currentTimeMillis());return "job3 test";});});System.out.println("main thread start cf.get(),time->"+System.currentTimeMillis());//等待子任务执行完成System.out.println("cf run result->"+cf.get());System.out.println("main thread start cf2.get(),time->"+System.currentTimeMillis());System.out.println("cf2 run result->"+cf2.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

其输出如下:

 

job1执行完成后job2开始执行,等job2执行完成后会把job3返回,然后执行job3,等job3执行完成后,主线程退出。

4、allOf / anyOf

allOf返回的CompletableFuture是多个任务都执行完成后才会执行,只有有一个任务执行异常,则返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回null。

    @Testpublic void test14() throws Exception {// 创建异步执行任务:CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start job1,time->"+System.currentTimeMillis());try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job1,time->"+System.currentTimeMillis());return 1.2;});CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start job2,time->"+System.currentTimeMillis());try {Thread.sleep(1500);} catch (InterruptedException e) {}System.out.println(Thread.currentThread()+" exit job2,time->"+System.currentTimeMillis());return 3.2;});CompletableFuture<Double> cf3 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread()+" start job3,time->"+System.currentTimeMillis());try {Thread.sleep(1300);} catch (InterruptedException e) {throw new RuntimeException("test");}System.out.println(Thread.currentThread()+" exit job3,time->"+System.currentTimeMillis());return 2.2;});//allof等待所有任务执行完成才执行cf4,如果有一个任务异常终止,则cf4.get时会抛出异常,都是正常执行,cf4.get返回null//anyOf是只有一个任务执行完成,无论是正常执行或者执行异常,都会执行cf4,cf4.get的结果就是已执行完成的任务的执行结果CompletableFuture cf4=CompletableFuture.allOf(cf,cf2,cf3).whenComplete((a,b)->{if(b!=null){System.out.println("error stack trace->");b.printStackTrace();}else{System.out.println("run succ,result->"+a);}});System.out.println("main thread start cf4.get(),time->"+System.currentTimeMillis());//等待子任务执行完成System.out.println("cf4 run result->"+cf4.get());System.out.println("main thread exit,time->"+System.currentTimeMillis());}

 其输出如下:

 主线程等待最后一个job1执行完成后退出。anyOf返回的CompletableFuture是多个任务只要其中一个执行完成就会执行,其get返回的是已经执行完成的任务的执行结果,如果该任务执行异常,则抛出异常。将上述测试用例中allOf改成anyOf后,其输出如下:

 


http://chatgpt.dhexx.cn/article/Grla3jdN.shtml

相关文章

2022.2.5 第十三次周报

文章目录 前言一、论文阅读《ROCKET: Exceptionally fast and accurate time series classification using random convolutional kernels》Abstract摘要Introduction介绍Method方法Kernels内核Transform转换Classifier分类器Complexity Analysis复杂性分析 Experiments实验Con…

并发编程(十五)-CompletableFuture中常用方法的使用与分析

文章目录 一、CompletableFuture API介绍1. 描述2. CompletionStage3. CompletableFuture 4个核心静态方法&#xff08;1&#xff09;runAsync(Runnable runnable)&#xff08;2&#xff09;runAsync(Runnable runnable, Executor executor)&#xff08;3&#xff09;supplyAsy…

Java 编程问题:十一、并发-深入探索

原文&#xff1a;Java Coding Problems 协议&#xff1a;CC BY-NC-SA 4.0 贡献者&#xff1a;飞龙 本文来自【ApacheCN Java 译文集】&#xff0c;自豪地采用谷歌翻译。 本章包括涉及 Java 并发的 13 个问题&#xff0c;涉及 Fork/Join 框架、CompletableFuture、ReentrantLock…

线程(十二)---CompletableFuture(三)

写在前面&#xff1a;各位看到此博客的小伙伴&#xff0c;如有不对的地方请及时通过私信我或者评论此博客的方式指出&#xff0c;以免误人子弟。多谢&#xff01; 示例五&#xff1a;异常处理 接着上一篇记录一下CompletableFuture的异常处理&#xff0c;异常处理通常使用…

dice loss

Dice Loss 最先是在VNet 这篇文章中被提出&#xff0c;后来被广泛的应用在了医学影像分割之中。 Dice 系数 Dice系数作为损失函数的原因和混淆矩阵有着很大的关系&#xff0c;下图给出的是一个混淆矩阵&#xff1a; 其中的一些关键指标如下&#xff1a; 精确率(precision)表…

Hinge loss

声明&#xff1a; 参考自维基百科后面可能会更新 Hinge Loss 在机器学习中&#xff0c;hinge loss作为一个损失函数(loss function)&#xff0c;通常被用于最大间隔算法(maximum-margin)&#xff0c;而最大间隔算法又是SVM(支持向量机support vector machines)用到的重要算法…

【深度学习】一文读懂机器学习常用损失函数(Loss Function)

【深度学习】一文读懂机器学习常用损失函数&#xff08;Loss Function&#xff09; 最近太忙已经好久没有写博客了&#xff0c;今天整理分享一篇关于损失函数的文章吧&#xff0c;以前对损失函数的理解不够深入&#xff0c;没有真正理解每个损失函数的特点以及应用范围&#x…

Pytorch之loss(损失函数)

损失函数也在torch.nn下&#xff0c;具体可以参考文档&#xff0c;也可以参考官网 先根据L1Loss举例 我个人感觉这里的描述还是到官网的文档找比较好&#xff0c;公式看的比文档清楚 import torch from torch import nninputs torch.tensor([[3, 2, 1],[1, 2, 3]], dtypetorch…

机器学习 损失函数 Loss function

损失函数 最小二乘法极大似然估计法交叉熵 【本文根据B站-王木头学科学-视频所学】 在梯度下降中&#xff0c;所求的梯度其实就是损失函数的梯度。 损失函数有三种设计方法&#xff1a; &#xff08;1&#xff09;最小二乘法 &#xff08;2&#xff09;极大似然估计法 &#x…

Focal loss 损失函数详解

Focal loss 目前目标检测的算法大致分为两类&#xff0c;One Stage 、Two Stage。 One Stage&#xff1a;主要指类似YOLO、SGD等这样不需要region proposal,直接回归的检测算法&#xff0c;这类算法检测速度很快&#xff0c;但是精度准确率不如使用Two stage的模型。 two St…

机器学习之常见的损失函数(loss function)

解决一个机器学习问题主要有两部分&#xff1a;数据和算法。而算法又有三个部分组成&#xff1a;假设函数、损失函数、算法优化。我们一般在看算法书或者视频教学时&#xff0c;更多的是去推算或者说参数估计出其假设函数&#xff0c;而往往不太注重损失函数&#xff0c;但是损…

深度学习loss函数理解

机器学习中的范数规则化之L0、L1、L2范数及loss函数 监督机器学习问题无非就是“minimizeyour error while regularizing your parameters”&#xff0c;也就是在规则化参数的同时最小化误差。 最小化误差是为了让我们的模型拟合我们的训练数据&#xff0c;而规则化参数是防止我…

CE Loss,BCE Loss以及Focal Loss的原理理解

一、交叉熵损失函数&#xff08;CE Loss&#xff0c;BCE Loss&#xff09; 最开始理解交叉熵损失函数被自己搞的晕头转向的&#xff0c;最后发现是对随机变量的理解有偏差&#xff0c;不知道有没有读者和我有着一样的困惑&#xff0c;所以在本文开始之前&#xff0c;先介绍一下…

损失函数loss

http://blog.csdn.net/pipisorry/article/details/23538535 监督学习及其目标函数 损失函数&#xff08;loss function&#xff09;是用来估量你模型的预测值f(x)与真实值Y的不一致程度&#xff0c;它是一个非负实值函数&#xff0c;通常使用L(Y, f(x))来表示。 损失函数是经…

机器学习模型中的损失函数loss function

1. 概述 在机器学习算法中&#xff0c;有一个重要的概念就是损失函数&#xff08;Loss Function&#xff09;。损失函数的作用就是度量模型的预测值 f ( x ) f\left ( \mathbf{x} \right ) f(x)与真实值 y \mathbf{y} y之间的差异程度的函数&#xff0c;且是一个非负实值函数。…

损失函数(Loss)

如果我们定义了一个机器学习模型&#xff0c;比如一个三层的神经网络&#xff0c;那么就需要使得这个模型能够尽可能拟合所提供的训练数据。但是我们如何评价模型对于数据的拟合是否足够呢&#xff1f;那就需要使用相应的指标来评价它的拟合程度&#xff0c;所使用到的函数就称…

focal loss详解

文章目录 focal loss的整体理解易分辨样本、难分辨样本的含义focal loss的出现过程focal loss 举例说明focal loss的 α \alpha α变体 focal loss的整体理解 focal loss 是一种处理样本分类不均衡的损失函数&#xff0c;它侧重的点是根据样本分辨的难易程度给样本对应的损失添…

深度学习——损失函数(Regression Loss、Classification Loss)

简介 Loss function 损失函数 用于定义单个训练样本与真实值之间的误差 Cost function 代价函数 用于定义单个批次/整个训练集样本与真实值之间的误差 Objective function 目标函数 泛指任意可以被优化的函数 损失函数用于衡量模型所做出的预测离真实值(GT)之间的偏离程度。 …

深度学习中常见的损失函数(L1Loss、L2loss)

损失函数定义 损失函数&#xff1a;衡量模型输出与真实标签的差异。 L1_loss 平均绝对误差&#xff08;L1 Loss&#xff09;:平均绝对误差&#xff08;Mean Absolute Error,MAE&#xff09;是指模型预测值f(x)和真实值y之间距离的平均值&#xff0c;公式如下&#xff1a; 优…

损失函数(loss function)

文章目录 1、什么是损失函数2、为什么要使用损失函数3、损失函数分类1、分类一2、分类二3、分类三3.1基于距离度量的损失函数3.1.1 均方误差损失函数&#xff08;MSE&#xff09;3.1.2 L2损失函数3.1.3 L1损失函数3.1.4 Smooth L1损失函数3.1.5 huber损失函数 3.2 基于概率分布…