• 使用CompletableFuture进行异步任务编排


    1.JDK5引入了Future进行异步任务的处理,Future 的接口主要方法有以下几个:

    (1)boolean cancel (boolean mayInterruptIfRunning) 取消任务的执行。参数指定是否立即中断任务执行,或者等等任务结束

    (2)boolean isCancelled () 任务是否已经取消,任务正常完成前将其取消,则返回 true

    (3)boolean isDone () 任务是否已经完成。需要注意的是如果任务正常终止、异常或取消,都将返回true

    (4)V get () throws InterruptedException, ExecutionException 等待任务执行结束,然后获得V类型的结果。InterruptedException 线程被中断异常, ExecutionException任务执行异常,如果任务被取消,还会抛出CancellationException

    (5) get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计 算超时,将抛出TimeoutException

    一般情况下Future 配合Callable 使用,获取异步任务执行的结果,一般使用get()方法设置超时时间,但是在任务执行结束前的这段时间内线程是阻塞的,也就不说异步的了。同时为了获取一般只能采取轮询isDone()方法,这样就显得使用方法很单一,无法适应复杂情况下的异步任务编排。

    2.JDK8 引入了CompletableFuture 来进行异步任务的编排,克服了Future的一些缺点,并且且进行了很多扩展。下面对CompletableFuture进行一个小的总结。
    3.CompletableFuture 的方法主要有以下几个特点:
    (1)以Async结尾的方法都是异步执行的
    (2)以run开头的方法一般无返回值,而已supply开头的方法是有返回值的,如 runAsync 和supplyAsync
      (3)   以 then 开头的方法都会在上一个任务执行结束之后执行下一个任务。如 thenApply 和 thenAccept
    (4)以Accept结尾的方法均为消耗上个任务执行的结果,无返回值。
    (5)以run开头的方法忽略上个任务的执行结果,在上个任务执行结束后执行下个方法。
    (6)以Executor 结尾的方法可以自定义线程池,如果没有指定线程池,则会默认在ForkJoinPool.commonPool() 线程池中执行。
    4.具体实例
    (1) 任务执行类的方法
    • RunAsync 执行异步任务,无返回值
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    
    /**
     * @Author lizhilong
     * @create 2019/11/18 18:07
     * @desc
     * runAsyn 无返回结果,执行get()方法时,任务被触发。
     */
    public class RunAsync {
        public  static  void  main(String [] args) {
            CompletableFuture<Void> future = CompletableFuture.runAsync(()->{
                System.out.println("Hello");
            });
            System.out.println("--------------");
            try {
                future.get();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    • SupplyAsync 执行异步任务,有返回值
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/18 18:17
     * @desc supplyAsync 方法有返回值,在get()方法后被触发
     */
    public class SupplyAsync {
        public  static void main(String[] args){
            CompletableFuture<String> future1 = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    return "Hello";
                }
            });
    
            System.out.println("-------------");
    
            try {
                String s = future1.get();
                System.out.println(s);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    • thenApply 在上个方法执行结束后将返回值作为入参执行下个方法
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/18 18:41
     * @desc
     * 以Async结尾的方法都会异步执行
     * thenApply/thenApplyAsync 会在上个方法执行完之后然后继续执行
     */
    public class ThenApply {
        public static void main(String[] args) {
    
            CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(3000);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    return "Hello";
                }
            }).thenApplyAsync(s1 -> {
              return  s1+"=="+"World";
            });
    
            try {
                String s = future.get();
                System.out.println(s);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    运行结果

    Hello==World
    • ThenAccept 消耗上个任务执行的结果,无返回值。
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/18 19:20
     * @desc
     * thenAccept 对上个任务产生的结果进行消耗,与ThenApply 不同的是无返回结果
     * 所以第二个thenAccept 返回 null
     */
    public class ThenAccept {
        public static void main(String[] args) {
            CompletableFuture<Void> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    return "hello";
                }
            }).thenAccept(s1 -> System.out.println(s1+" world"))
                    .thenAccept(s2-> System.out.println("---"+s2));
    
            try {
                future.get();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    执行结果:

    hello world
    ---null
    • ThenRun 不关心上一步的执行结果,在上一步任务执行结束后执行下一步任务
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/19 11:44
     * @desc thenRun 不关心上一步执行的结果,上一步执行结束后执行下一步
     * thenRunAsync 异步执行
     */
    public class ThenRun {
    
        public static void main(String[] args) {
            CompletableFuture<Void> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(3000);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    return "Hello";
                }
            }).thenRunAsync(new Runnable() {
                @Override
                public void run() {
                    System.out.println("World");
                }
            });
    
            try {
                future.get();
            }catch (Exception e ){
                e.printStackTrace();
            }
    
        }
    }

    运行结果:

    World
    • ThenApplyWithExecutor 在自定义的线程池执行异步任务
    package completablefuture;
    
    import java.util.concurrent.*;
    
    /**
     * @Author lizhilong
     * @create 2019/11/18 18:59
     * @desc
     * 自定义线程池的方式来处理有先后顺序的任务
     */
    public class ThenApplyWithExecutor {
    
        public static void main(String[] args) {
            ExecutorService service = Executors.newCachedThreadPool();
    
            CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{
                return "Hello";
            },service).thenApplyAsync(s1->{
                return s1 + "   World";
            },service).thenApplyAsync(s2 ->{
                return s2 +"    China";
            },service);
    
            try {
                String s = future.get();
                System.out.println(s);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                service.shutdownNow();
            }
        }
    }

    运行结果:

    Hello   World    China
    • runAfterBoth/runAfterBothAsync 在前面任务执行结束后执行新的任务
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/19 15:33
     * @desc runAfterBothAsync 忽略前面任务的执行结果,在前面任务执行结束之后在执行后面的runable任务
     */
    public class RunAfterBothAsync {
        public static void main(String[] args) {
            CompletableFuture<Void> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println("st1 end");
                    return "Hello";
                }
            }).runAfterBothAsync(CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(7000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println("st2 end");
                    return "World";
                }
            }), new Runnable() {
                @Override
                public void run() {
                    System.out.println("I LOVE CHINA");
                }
            });
    
            try {
                future.get();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    运行结果:

    st1 end
    st2 end
    I LOVE CHINA

    (2)任务结果消费/组合

    • thenCombine/thenCombineAsync 任务的运行结果进行组合后输出
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/19 13:40
     * @desc thenCombineAsync 将任务的执行结果进行合并后输出
     * 最后的合并必操作须等两个任务都执行结束后才可以进行
     */
    public class CompletionStage {
    
        public static void main(String[] args) {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println("st1 end");
                    return "Hello";
                }
            }).thenCombineAsync(
                    CompletableFuture.supplyAsync(new Supplier<String>() {
                                                      @Override
                                                      public String get() {
                                                          try {
                                                              Thread.sleep(7000);
                                                          } catch (Exception e) {
                                                              e.printStackTrace();
                                                          }
                                                          System.out.println("st2 end");
                                                          return "World";
                                                      }
                                                  }
                    ), (r1, r2) -> r1 + " " + r2);
    
            try {
                String s = future.get();
                System.out.println(s);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }

    运行结果:

    st1 end
    st2 end
    Hello World
    • ThenAcceptBothAsync 对异步任务的执行结果进行消耗,无返回值
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/19 14:59
     * @desc thenAcceptBothAsync 消费任务的执行结果,无返回值
     * 消费动作的执行发生在任务均完成的情况下
     */
    public class ThenAcceptBothAsync {
        public static void main(String[] args) {
            CompletableFuture<Void> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println("st1 end");
                    return "Hello";
                }
            }).thenAcceptBothAsync(CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(7000);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    System.out.println("st2 end");
                    return "World";
                }
            }) ,(r1, r2) -> System.out.println(r1 +" "+r2));
    
            try {
                future.get();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    运行结果:

    st1 end
    st2 end
    Hello World

    (3)根据任务执行完成的先后顺讯进行后续操作

    • applyToEither/applyToEitherAsync 获取最先执行完成的任务的结果
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/19 15:43
     * @desc ApplyToEitherAsync 获取多个任务执行最快的任务结果
     */
    public class ApplyToEitherAsync {
        public static void main(String[] args) {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println("st1 end");
                    return "CHINA";
                }
            }).applyToEitherAsync(CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(7000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println("st2 end");
                    return "AUS";
                }
            }), (r) -> {
                return r;
            }).applyToEitherAsync(CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(2000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println("st3 end");
                    return "UK";
                }
            }), r1->{
                return  r1;
            });
    
            try {
                String s = future.get();
                System.out.println(s);
            }catch (Exception e){
                e.printStackTrace();
            }
    
        }
    }

    运行结果:

    st3 end
    UK
    • acceptEither/acceptEitherAsync 消耗最先执行完的任务的返回结果
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/19 16:13
     * @desc AcceptEitherAsync 消费最先完成的任务返回的结果
     */
    public class AcceptEitherAsync {
    
        public static void main(String[] args) throws  Exception{
            CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return "Hello";
                }
            }).acceptEitherAsync( CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(5000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return "World";
                }
            }), System.out::println).get();
        }
    }

    运行结果:

    Hello
    • RunAfterEither/RunAfterEitherAsync 在前面的任务有任何一个完成后运行
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/19 18:28
     * @desc RunAfterEither 是在前面任务有一个完成以后再去执行的,即最先完成的任务后运行
     *
     */
    public class RunAfterEither {
        public static void main(String[] args) throws  Exception{
            CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println("st1 end");
                    return "Hello";
                }
            }).runAfterEitherAsync(CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    try {
                        Thread.sleep(5000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println("st2 end");
                    return "World";
                }
            }), new Runnable() {
                @Override
                public void run() {
                    System.out.println("I LOVE CHINA");
                }
            }).get();
        }
    }

    运行结果:

    st1 end
    I LOVE CHINA

    (4)任务完成时

    • complete 任务完成后执行后续操作
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    
    /**
     * @Author lizhilong
     * @create 2019/11/18 18:21
     * @desc 任务完成以后 执行后续操作
     */
    public class Complete {
    
        public static void main(String[] args) {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{
               return  "Hello";
            });
    
            future.complete("world");
            System.out.println("----------------");
            try {
                String s = future.get();
                System.out.println(s);
    
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    运行结果:

    ----------------
    world
    • whenCompleteAsync/whenComplete 在前面任务执行完成后执行后续操作,可以获取前面任务的执行结果和异常
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/19 18:46
     * @desc WhenComplete 任务完成后执行相应操作,可以获取上步任务执行的结果或者异常
     */
    public class WhenComplete {
    
        public static void main(String[] args) {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    if (1==2) {
                        throw new RuntimeException("测试异常");
                    }
                    return "Hello";
                }
            }).whenCompleteAsync((s, e) -> {
                System.out.println(s);
                System.out.println(e.getMessage());
            });
    
            try {
                String s = future.get();
                System.out.println(s);
            }catch (Exception e){
                System.out.println(e.getMessage());
            }
        }
    }

    运行结果:

    Hello
    java.lang.NullPointerException

    (5)任务执行异常

    • completeExceptionally 任务完成后抛异常
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/18 18:30
     * @desc 任务完成以后抛异常
     */
    public class CompleteExceptionally {
        public static void main(String[] args) {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    return "Hello";
                }
            });
    
            future.completeExceptionally( new Exception());
            try {
                String s = future.get();
                System.out.println(s);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    运行结果:

    java.util.concurrent.ExecutionException: java.lang.Exception
        at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
        at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
        at completablefuture.CompleteExceptionally.main(CompleteExceptionally.java:22)
    Caused by: java.lang.Exception
        at completablefuture.CompleteExceptionally.main(CompleteExceptionally.java:20)
    • exceptionally 执行任务过程中产生异常
    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/19 18:35
     * @desc 任务产生异常时进行相应操作
     */
    public class Exceptionally {
    
        public static void main(String[] args) {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    int x = 10 / 0;
                    return "Hello";
                }
            }).exceptionally(e -> {
                System.out.println(e.getMessage());
                return "World";
            });
    
            try {
                String s = future.get();
                System.out.println(s);
            }catch (Exception e){
    
            }
        }
    }

    运行结果:

    java.lang.ArithmeticException: / by zero
    World
    • handleAsync/handle 在使用 exceptionally 可以获取异常时的异常,但是无法获取正常执行时的结果
    异常:
     public static void main(String[] args) {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    if(true){
                        throw  new RuntimeException("测试异常");
                    }
                    return "Hello";
                }
            }).handleAsync((r, e) -> {
                if (e != null) {
                    return e.getMessage();
                }
                return "World";
            });
    
            try {
                System.out.println(future.get());
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    执行结果:

    java.lang.RuntimeException: 测试异常

    正常:

    package completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.function.Supplier;
    
    /**
     * @Author lizhilong
     * @create 2019/11/19 18:58
     * @desc
     */
    public class HandleNormal {
        public static void main(String[] args) {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    return "Hello";
                }
            }).handleAsync((r, e) -> {
                if (e != null) {
                    return e.getMessage();
                }
                return "World";
            });
    
            try {
                System.out.println(future.get());
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
    }

    执行结果:

    World
  • 相关阅读:
    获取checkboxlist多选值
    关于SQL Server 2005远程登录的问题。
    安装完vs2005后没有C#,VB.net,网站等模版的解决方法
    md5 加密
    C#中partial关键字
    C# 重载与覆盖
    CSS常用关键字汇总
    C#常用算法
    常用CSS样式属性
    Oracle 查询正在运行的SQL语句
  • 原文地址:https://www.cnblogs.com/li-zhi-long/p/11936642.html
Copyright © 2020-2023  润新知