使用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()方法,这样就显得使用方法很单一,无法适应复杂情况下的异步任务编排。
- 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