• 2021.04.30 异步线程优化用户体验


    背景

    对于后端开发,接口响应时长是一个很关键的点,它不仅体现了你写的接口的性能,同时也代表着用户体验,如果你的内容响应时间过长,用户可能早就把网页关闭了。

    互联网行业,有一个用户体验原则——2/5/10秒原则。

    就是说,在2秒之内给客户响应被用户认为是“非常有吸引力”的用户体验。

    在5秒之内响应客户被认为“比较不错”的用户体验,在10秒内给用户响应被认为“糟糕”的用户体验。

    如果超过10秒还没有得到响应,那么大多用户会认为这次请求是失败的。

    所以很多互联网企业,接口发布上线前,都有一个压测要求:特定并发量下,接口的响应时间不能大于200ms

    在这样的要求之下,想要提升接口性能,减少用户等待时间,将部分非实时、不重要、确定无异常等交易(比如订单处理、办理完某个业务给用户发消息等),设计成异步处理的方式是一个不错的选则,今天我们就来通过一个简单的示例演示,来了解下异步交易如何实现。

    异步交易演示

    假设,我们有这样的业务需求:

    场景一: 我们有一个教务管理系统,讲师导入创建了一门新的课程,并制定了学员,处理课程创建的操作外,我们还需要在课程创建成功后,给学员发消息。但是发消息并非是特别重要的操作,这时候我们就可以通过异步交易来发送消息。

    场景二:我们需要在用户注册成功后,给用户发送消息(邮件或短信)通知用户,和场景一类似,发送消息非必须业务,为了提升系统响应效率,这时候异步交易是个不错的选择。

    场景说完了,下来看我们的简单应用:

    我们先创建了一个线程池:

    private static ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(5, 10, 1,
                        TimeUnit.SECONDS, new LinkedBlockingQueue<>(5));
    

    然后,我们在核心交易的最后,通过线程池的submit启动了一个线程:

     threadPoolExecutor.submit(() -> this.sendMessage(messageList));
    

    通过这个线程去执行发消息的操作,这里我们用到了lamubda表达式,上面的代码等同于:

    threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    sendMessage(messageList);
                }
            });
    

    下面是完整代码:

    /**
     * @author syske
     * @date 2021-05-01 9:34
     */
    public class Example {
        private static ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(5, 10, 1,
                        TimeUnit.SECONDS, new LinkedBlockingQueue<>(5));
        /**
         * 发送消息
         * @param messageList 消息列表
         * @return
         */
        public AtomicInteger sendMessage(List<String> messageList) {
            AtomicInteger successCount = new AtomicInteger();
            messageList.forEach(m -> {
                System.out.println("发送消息:" + m);
                successCount.getAndIncrement();
            });
            return successCount;
        }
    
        /**
         * 核心业务处理
         * @return
         */
        public String deal() {
            List<String> messageList = new ArrayList<>();
            // doSomeThing() 其他业务处理
            System.out.println("开始组装消息~Start");
            for (int i = 0; i < 1000; i++) {
                int randomInt1 = new Random().nextInt();
                messageList.add("发送数字信息:" + randomInt1);
            }
            System.out.println("组装消息完成~End");
            System.out.println("开始发送消息~Start");
            threadPoolExecutor.submit(() -> this.sendMessage(messageList));
            System.out.println("发送消息完成~End");
            return "业务处理完成";
        }
    
        public static void main(String[] args) {
            Example example = new Example();
            String result = example.deal();
            System.out.println(result);
            threadPoolExecutor.shutdown();
        }
    }
    

    执行上面的方法,你会发现,核心业务方法在消息没发送就已经返回了:

    开始组装消息~Start
    组装消息完成~End
    开始发送消息~Start
    发送消息完成~End
    业务处理完成
    发送消息:发送数字信息:-123158837
    ……
    ……
    发送消息:发送数字信息:-1354635036
    

    这样我们的异步交易就实现了,是不是很简单呀,如果你的异步业务是有返回值的,那在启动线程的时候,你可以通过Callable来实现,它和Runnable没有本质区别,只是它是可以有返回值的。

    总结

    其实今天的内容很简单,实现过程也很容易,异步交易中真正难的是如何拆分你的业务,这就需要你自己多思考,多实践,多总结了,还是那句话会用这个工具很简单,但清楚什么时候用这个工具才更重要。好了,各位小伙伴节日快乐,好好享受假期,但也别忘了学习哦

    项目路径:

    https://github.com/Syske/example-everyday
    

    本项目会持续每日更新,让我们一起学习,一起进步,遇见更好的自己,加油呀

  • 相关阅读:
    linux下安装配置DHCP服务器
    CentOS7安装配置Apache HTTP Server
    CentOS7安装配置DNS服务器
    CentOS7安装配置SAMBA服务器
    小程序全局监听
    springboot+redis
    java对接微信小程序
    获取上一个页面的data
    定时器
    maven项目打包
  • 原文地址:https://www.cnblogs.com/caoleiCoding/p/14723959.html
Copyright © 2020-2023  润新知