随着业务倒退,底层数据量越来越大,业务逻辑也日趋复杂化,某些接口耗时也越来越长,这时候接口就须要进行性能优化了,当然性能优化次要跟业务相干波及革新点可能各不相同,这里就来介绍异步调用多个接口缩小响应工夫

实用条件

  • 调用多个独立的接口,接口间无相互依赖关系
  • 非耗时最大的接口占总耗时比重较大

优化前调用形式

优化前的代码依照顺序调用形式:

import lombok.extern.slf4j.Slf4j;@Slf4jpublic 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;        }    }}

执行后果:

21:40:17.603 [main] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2002ms21:40:19.612 [main] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2001ms21:40:19.613 [main] INFO DemoTest - 执行后果:2 耗时:4018

优化后调用形式

优化后的代码依照异步调用形式:

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;@Slf4jpublic 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;        }    }}

执行后果:

22:03:43.180 [线程名称-1] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2004ms22:03:43.180 [线程名称-0] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2004ms22:03:43.190 [main] INFO DemoTest - 执行后果:2 耗时:2020

此形式还能够联合CompletionService可实现异步工作和执行后果拆散,大家能够自行搜寻实际

弱小的CompletableFuture JDK1.8

import com.google.common.collect.Lists;import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;import java.util.List;import java.util.concurrent.CompletableFuture;@Slf4jpublic 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;        }    }}

执行后果:

22:31:44.822 [ForkJoinPool.commonPool-worker-5] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2005ms22:31:44.822 [ForkJoinPool.commonPool-worker-3] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2002ms22:31:44.831 [main] INFO DemoTest - 执行后果:2 耗时:2027

优化时留神点

  • 应用线程池避免内存溢出危险
  • 执行后果容器可自行依据须要设置
  • 接口粒度可依据理论业务状况组合和拆分