情况一 (各个子业务互不影响的情况)
这种情况,一般都循环调用同一段代码,每次循环的逻辑一致,前后不关联。
比如说,我们要初始化一个列表,预置 12 个月的数据给前端:
List<Model> list = new ArrayList<>();
for(int i = 0 ; i < 12 ; i ++) {
Model model = calOneMonthData(i); // 计算某个月的数据,逻辑比较复杂,难以批量计算,效率也无法很高
list.add(model);
}
这种显然每个月的数据计算相互都是独立的,我们完全可以采用多线程方式进行:
// 建立一个线程池,注意要放在外面,不要每次执行代码就建立一个,具体线程池的使用就不展开了
public static ExecutorService commonThreadPool = new ThreadPoolExecutor(5, 5, 300L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(10), commonThreadFactory, new ThreadPoolExecutor.DiscardPolicy());
// 开始多线程调用
List<Future<Model>> futures = new ArrayList<>();
for(int i = 0 ; i < 12 ; i ++) {
Future<Model> future = commonThreadPool.submit(() -> calOneMonthData(i););
futures.add(future);
}
// 获取结果
List<Model> list = new ArrayList<>();
try {
for (int i = 0 ; i < futures.size() ; i ++) {
list.add(futures.get(i).get());
}
} catch (Exception e) {
LOGGER.error("出现错误:", e);
}
情况二 (是情况一的特殊情况)
如果不是类似上面循环调用,而是一次次的顺序调用,而且调用之间没有结果上的依赖,那么也可以用多线程的方式进行,例如:
代码上看:
A a = doA();
B b = doB();
C c = doC(a, b);
D d = doD(c);
E e = doE(c);
return doResult(d, e);
那么可用 CompletableFuture 解决:
CompletableFuture<A> futureA = CompletableFuture.supplyAsync(() -> doA());
CompletableFuture<B> futureB = CompletableFuture.supplyAsync(() -> doB());
CompletableFuture.allOf(futureA,futureB) // 等a b 两个任务都执行完成
C c = doC(futureA.join(), futureB.join());
CompletableFuture<D> futureD = CompletableFuture.supplyAsync(() -> doD(c));
CompletableFuture<E> futureE = CompletableFuture.supplyAsync(() -> doE(c));
CompletableFuture.allOf(futureD,futureE) // 等d e两个任务都执行完成
return doResult(futureD.join(),futureE.join());
这样 A B 两个逻辑可以并行执行,D E 两个逻辑可以并行执行,最大执行时间取决于哪个逻辑更慢。