使用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

猜你喜欢

转载自www.cnblogs.com/li-zhi-long/p/11936642.html