问题一、接口逻辑复杂请求慢情景分析

一、接口示例

        1、执行体:

    //sleep1 1s  sleep2 5s  sleep3 10s 顺序执行
    public void question1() {
        log.info("开始: "+simpleFormat.format(new Date()));
        thirdHttpComponrent.sleep1();
        thirdHttpComponrent.sleep2();
        thirdHttpComponrent.sleep3();
        log.info("结束: "+simpleFormat.format(new Date()));
    }

        2、调用方:

    public void sleep1(){

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("睡眠1秒钟: "+simpleFormat.format(new Date()));
    }

    public void sleep2(){

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("睡眠5秒钟: "+simpleFormat.format(new Date()));
    }

    public void sleep3(){

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("睡眠10秒钟: "+simpleFormat.format(new Date()));
    }

        3、结论:

        顺序执行,所需时间为16s,为三者之和。

二、可行性方案

        1、没返回值:异步执行,前后端分离,避免请求阻塞,占用资源。

                1.1、调用方加上注解@Async:

    @Async
    public void sleep1(){

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("睡眠1秒钟: "+simpleFormat.format(new Date()));
    }

                1.2、main入口,加上@EnableAsync:

@SpringBootApplication
@EnableAsync
public class TestQuestionsApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestQuestionsApplication.class, args);
    }

}

                1.3、结论:

                异步执行,所需时间为10s,为三者之最;执行体执行完非异步逻辑,便立即返回

        2、有返回值:后端异步执行,缓存结果(redis...),前端间断多次请求取值

                2.1、执行体:

    public HashMap question2(String key) {
        if(!StringUtils.isEmpty(key)){
            return (HashMap)hashMap.get(key);
        }

        key = UUID.randomUUID()+"";
        HashMap result = new HashMap();
        result.put("key",key);

        thirdHttpComponrent.sleep4(result);
        thirdHttpComponrent.sleep5(result);
        thirdHttpComponrent.sleep6(result);

        hashMap.put(key,result);
        return (HashMap)hashMap.get(key);
    }

                2.2、调用方:

@Async
    public void sleep4(HashMap hashMap){

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        hashMap.put("sleep4","sleep4");
        log.info("睡眠1秒钟: "+simpleFormat.format(new Date()));
    }

    @Async
    public void sleep5(HashMap hashMap){

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        hashMap.put("sleep5","sleep5");
        log.info("睡眠5秒钟: "+simpleFormat.format(new Date()));
    }

    @Async
    public void sleep6(HashMap hashMap){

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        hashMap.put("sleep6","sleep6");
        log.info("睡眠10秒钟: "+simpleFormat.format(new Date()));
    }

                2.3、结论:

                有返回值慢接口,后端异步缓存结果,前端多次取值,避免了请求超时,长时间占用资源、阻塞线程等问题。

1,2次返回
{
    "key": "d8f90881-4084-41f8-a763-f5da6aa1b327"
}


3....次返回
{
    "sleep5": "sleep5",
    "sleep6": "sleep6",
    "sleep4": "sleep4",
    "key": "d8f90881-4084-41f8-a763-f5da6aa1b327"
}

        3、接口业务逻辑相互关联不大:多个线程并发执行,最后统一结果返回

                3.1、执行体:

    private volatile static int i = 0;

    private synchronized Integer getI(){
        return i++;
    }

    @Override
    public void question3() throws InterruptedException {

        // 处理队列,需要处理的数据,放置到此队列中
        Queue<Integer> queue = new ConcurrentLinkedQueue<>();
        // 进队 执行 线程数
        CountDownLatch offerLatch = new CountDownLatch(3);
        // 出队 执行 线程数
        CountDownLatch pollLatch = new CountDownLatch(1);

        Runnable offerRunnable = () -> {

            try {
                // 循环取数
                while (true) {
                    Integer offerI = this.getI();
                    queue.offer(offerI);
                    Thread.sleep(10000);
                    if(offerI == 10) {
                        break;
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 在finally中执行latch.countDown()以及信号量释放,避免因异常导致没有正常释放
                offerLatch.countDown();
            }
        };

        Runnable pollRunnable = () -> {
            try {
                // 只要offer的latch未执行完,或queue仍旧有数据,则继续循环
                while (offerLatch.getCount() > 0 || queue.size() > 0) { 
                    Integer poll = queue.poll();
                    if (poll != null) {
                        System.out.println(poll);
                    }
                    // 无论是否poll到数据,均暂停一小段时间,可降低CPU消耗
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                // 在finally中执行latch.countDown(),避免因异常导致没有正常释放
                pollLatch.countDown();
            }
        };

        // 启动一个poll线程   模拟取数据很慢,需要开启3个线程处理
        new Thread(pollRunnable).start();
        for (int i = 0; i < 3; i++) {
            new Thread(offerRunnable).start();
        }

        // latch等待,直到latch的count为0
        offerLatch.await();
        pollLatch.await();

        System.out.println("结束");

    }

                3.2、结论:

                接口业务逻辑相互关联不大,多个线程同时并发执行,提高响应时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值