随着业务发展,底层数据量越来越大,业务逻辑也日趋复杂化,某些接口耗时也越来越长,这时候接口就需要进行性能优化了,当然性能优化主要跟业务相关涉及改造点可能各不相同,这里就来介绍异步调用多个接口减少响应时间。
适用条件
- 调用多个独立的接口,接口间无相互依赖关系
- 非耗时最大的接口占总耗时比重较大
优化前调用方式
优化前的代码按照顺序调用方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import lombok.extern.slf4j.Slf4j;
@Slf4j public class DemoTest { public static void main(String[] args) throws Exception { long beginTime = System.currentTimeMillis(); int processA = new InterfaceA().process(); int processB = new InterfaceB().process(); int result = processA + processB; log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime); } @Slf4j public final static class InterfaceA { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceA.process Exception"); } log.info("执行接口InterfaceA.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } } @Slf4j public final static class InterfaceB { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceB.process Exception"); } log.info("执行接口InterfaceB.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } } }
|
执行结果:
1 2 3
| 21:40:17.603 [main] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2002ms 21:40:19.612 [main] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2001ms 21:40:19.613 [main] INFO DemoTest - 执行结果:2 耗时:4018
|
优化后调用方式
优化后的代码按照异步调用方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| import cn.hutool.core.thread.ThreadFactoryBuilder; import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Future; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit;
@Slf4j public class DemoTest { private static ThreadPoolExecutor pool = new ThreadPoolExecutor( 5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000), ThreadFactoryBuilder.create().setNamePrefix("线程名称-").build() ); public static void main(String[] args) throws Exception { long beginTime = System.currentTimeMillis(); List<Future<Integer>> futures = new ArrayList<>(2); List<Integer> results = new ArrayList<>(2); futures.add(pool.submit(() -> new InterfaceA().process())); futures.add(pool.submit(() -> new InterfaceB().process())); for (Future<Integer> item : futures) { results.add(item.get()); } int result = results.get(0) + results.get(1); log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime); } @Slf4j public final static class InterfaceA { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceA.process Exception"); } log.info("执行接口InterfaceA.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } } @Slf4j public final static class InterfaceB { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceB.process Exception"); } log.info("执行接口InterfaceB.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } } }
|
执行结果:
1 2 3
| 22:03:43.180 [线程名称-1] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2004ms 22:03:43.180 [线程名称-0] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2004ms 22:03:43.190 [main] INFO DemoTest - 执行结果:2 耗时:2020
|
此方式还可以结合CompletionService可实现异步任务和执行结果分离,大家可以自行搜索实践
强大的CompletableFuture JDK1.8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture;
@Slf4j public class DemoTest { public static void main(String[] args) throws Exception { long beginTime = System.currentTimeMillis(); CompletableFuture<Integer> interfaceFuturesA = CompletableFuture.supplyAsync(() -> new InterfaceA().process()); CompletableFuture<Integer> interfaceFuturesB = CompletableFuture.supplyAsync(() -> new InterfaceB().process()); CompletableFuture<List<Integer>> future = CompletableFuture .allOf(interfaceFuturesA, interfaceFuturesB) .thenApply((none) -> { List<Integer> dataList = new ArrayList<>(2); try { dataList.add(interfaceFuturesA.get()); dataList.add(interfaceFuturesB.get()); } catch (Exception e) { log.error("执行异常"); } return dataList; }).exceptionally(e -> Lists.newArrayList()); int result = future.get().get(0) + future.get().get(1); log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime); } @Slf4j public final static class InterfaceA { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceA.process Exception"); } log.info("执行接口InterfaceA.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } } @Slf4j public final static class InterfaceB { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceB.process Exception"); } log.info("执行接口InterfaceB.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } } }
|
执行结果:
1 2 3
| 22:31:44.822 [ForkJoinPool.commonPool-worker-5] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2005ms 22:31:44.822 [ForkJoinPool.commonPool-worker-3] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2002ms 22:31:44.831 [main] INFO DemoTest - 执行结果:2 耗时:2027
|
优化时注意点
- 使用线程池防止内存溢出风险
- 执行结果容器可自行根据需要设置
- 接口粒度可根据实际业务情况组合和拆分