1 直接上代码吧。java版本的。
背景是我有一个需求是用户注销。注销时我需要判断是否有订单,结算单等业务。这样我就需要调用其他业务线的接口。
接口需要调用N个(这里是5个)分别判断是否允许注销。
悲观假设每个接口调用要1s那么5个接口就需要5s以上,并且任何一个不可行则整个判断将不通过。
这时候就需要用到异步任务并行。 这里采用
CompletableFuture的thenCombine 来实现多个异步任务并行。代码简单。将两个test跑一下就可以看到效果,
异常case是将userId写成 >100的值。第4个任务将会抛错。这样就可以看到整体运行结果。
当然抛错也可以转换为自己认识的错误方式,由调用方来决定是否继续往下走。
2 
 3 import java.util.concurrent.CompletableFuture;
 4 import lombok.extern.slf4j.Slf4j;
 5 import org.junit.Test;
 6 
 7 @Slf4j
 8 public class SupplyAsyncText {
 9 
10   @Test
11   public void testSyncLogOff() {
12     int userId = 45;
13     // 同步
14     long begin = System.currentTimeMillis();
15     StringBuilder sb = new StringBuilder();
16     sb.append(canDo1(userId));
17     sb.append(canDo2(userId));
18     sb.append(canDo3(userId));
19     sb.append(canDo4(userId));
20     sb.append(canDo5(userId));
21     long end = System.currentTimeMillis();
22     // 每一个执行1s 同步:结果是执行应该是 > 5s 的
23     log.info("noUseAsync |{}|{} s", sb.toString(), (end - begin) / 1000.0);
24   }
25 
26   @Test
27   public void testCanLogOff() {
28     // case 设定:如果 userId > 100 则在某一个环节抛错
29     int userId = 10;
30     // 异步 每一个执行1s 异步并行:结果是执行应该 < 5s
31     long begin2 = System.currentTimeMillis();
32     String result =
33         CompletableFuture.supplyAsync(() -> canDo1(userId))
34             .thenCombine(CompletableFuture.supplyAsync(() -> canDo2(userId)), (s1, s2) -> s1 + s2)
35             .thenCombine(CompletableFuture.supplyAsync(() -> canDo3(userId)), (s1, s2) -> s1 + s2)
36             .thenCombine(CompletableFuture.supplyAsync(() -> canDo4(userId)), (s1, s2) -> s1 + s2)
37             .thenCombine(CompletableFuture.supplyAsync(() -> canDo5(userId)), (s1, s2) -> s1 + s2)
38             .exceptionally(
39                 e -> {
40                   log.error("exception: ", e);
41                   return e.getMessage();
42                 })
43             .join();
44     long end2 = System.currentTimeMillis();
45     log.info("supplyAsync|{}|{} s", result, (end2 - begin2) / 1000.0);
46   }
47 
48   private String canDo1(int userId) {
49     try {
50       Thread.sleep(1000);
51     } catch (InterruptedException e) {
52       e.printStackTrace();
53     }
54     return "ok";
55   }
56 
57   private String canDo2(int userId) {
58     try {
59       Thread.sleep(1000);
60     } catch (InterruptedException e) {
61       e.printStackTrace();
62     }
63     return "ok";
64   }
65 
66   private String canDo3(int userId) {
67     try {
68       Thread.sleep(1000);
69     } catch (InterruptedException e) {
70       e.printStackTrace();
71     }
72     return "ok";
73   }
74 
75   private String canDo4(int userId) {
76     try {
77       Thread.sleep(1000);
78     } catch (InterruptedException e) {
79       e.printStackTrace();
80     }
81     if (userId > 100) {
82       throw new RuntimeException(String.format("用户[%s]还有订单,不可注销",userId));
83     }
84     return "ok";
85   }
86 
87   private String canDo5(int userId) {
88     try {
89       Thread.sleep(1000);
90     } catch (InterruptedException e) {
91       e.printStackTrace();
92     }
93     return "ok";
94   }
95 }