java8的parallelStream提升数倍查询效率

栏目: IT技术 · 发布时间: 4年前

内容简介:在很多项目中,都有类似数据汇总的业务场景,查询今日注册会员数,在线会员数,订单总金额,支出总金额等。。。这些业务通常都不是存在同一张表中,我们需要依次查询出来然后封装成所需要的对象返回给前端。那么在此过程中,就可以把这个接口中“大任务”拆分成N个小任务,异步执行这些小任务,等到最后一个小任务执行完,把所有任务的执行结果封装到返回结果中,统一返回到前端展示。首先看看同步执行的代码执行时长想必大家都能够想得到,理所应当是10秒以上

业务场景

在很多项目中,都有类似数据汇总的业务场景,查询今日注册会员数,在线会员数,订单总金额,支出总金额等。。。这些业务通常都不是存在同一张表中,我们需要依次查询出来然后封装成所需要的对象返回给前端。那么在此过程中,就可以把这个接口中“大任务”拆分成N个小任务,异步执行这些小任务,等到最后一个小任务执行完,把所有任务的执行结果封装到返回结果中,统一返回到前端展示。

同步执行

首先看看同步执行的代码

public class Test {


    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    class Result {
        /**
         * 在线人数
         */
        Integer onlineUser;

        /**
         * 注册人数
         */
        Integer registered;

        /**
         * 订单总额
         */
        BigDecimal orderAmount;

        /**
         * 支出总额
         */
        BigDecimal outlayAmount;
    }

    @org.junit.Test
    public void collect() {
        System.out.println("数据汇总开始");
        long startTime = System.currentTimeMillis();
        Integer onlineUser = queryOnlineUser();
        Integer registered = queryRegistered();
        BigDecimal orderAmount = queryOrderAmount();
        BigDecimal outlayAmount = queryOutlayAmount();
        Result result = new Result(onlineUser, registered, orderAmount, outlayAmount);
        long endTime = System.currentTimeMillis();
        System.out.println("获取汇总数据结束,result = " + result);
        System.out.println("总耗时 = " + (endTime - startTime) + "毫秒");
    }

    public Integer queryOnlineUser() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("查询在线人数 耗时2秒");
        return 10;
    }

    public Integer queryRegistered() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("查询注册人数 耗时2秒");
        return 10086;
    }

    public BigDecimal queryOrderAmount() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("查询订单总额 耗时3秒");
        return BigDecimal.valueOf(2000);
    }

    public BigDecimal queryOutlayAmount() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("查询支出总额 耗时3秒");
        return BigDecimal.valueOf(1000);
    }

}

执行时长想必大家都能够想得到,理所应当是10秒以上

数据汇总开始
查询在线人数 耗时2秒
查询注册人数 耗时2秒
查询订单总额 耗时3秒
查询支出总额 耗时3秒
获取汇总数据结束,result = Test.Result(onlineUser=10, registered=10086, orderAmount=2000, outlayAmount=1000)
总耗时 = 10008毫秒

异步执行

下面换成异步执行,用 java 8的parallelStream(并行流),这里为什么不用Thread呢, 这里有一个注意点,我们需要获取所有所有子任务执行完的时间点,在这个时间点之后才能将结果封装返回 ,Thread没有办法满足,这里parallelStream和函数式接口就登场了。

java8的特性之一 —— lambda表达式,就是配合函数式接口使用的。

java8内置了四大核心函数式接口:

1、Consumer<T>   : 消费型接口    void accept(T t);

2、Supplier<T>      : 供给型接口    T get();

3、Function<T,R>   : 函数型接口    R apply(T t);

4、Predicate<T>    : 断言型接口    boolean test(T t);

这四大核心函数式接口其下还有很多子接口,基本上能满足日常项目所用,这里扯远了。。   直接上代码。

这里我们需要使用的是Runable接口,是无参无返回值的一个接口。在实际场景中,可能有时间范围之类的查询参数的,则可以根据不同业务使用不同的接口。这种方式也可以用Future接口去实现,有兴趣的可以试一试,这里就不多做叙述了。

@org.junit.Test
public void collect() {
    System.out.println("数据汇总开始");
    long startTime = System.currentTimeMillis();
    Result result = new Result();
    List<Runnable> taskList = new ArrayList<Runnable>() {
        {
            add(() -> result.setOnlineUser(queryOnlineUser()));
            add(() -> result.setRegistered(queryRegistered()));
            add(() -> result.setOrderAmount(queryOrderAmount()));
            add(() -> result.setOutlayAmount(queryOutlayAmount()));
        }
    };
    taskList.parallelStream().forEach(v -> v.run());
    long endTime = System.currentTimeMillis();
    System.out.println("获取汇总数据结束,result = " + result);
    System.out.println("总耗时 = " + (endTime - startTime) + "毫秒");
}

执行结果,由于四个子任务都是并行的,效率直接提升了三倍,如果子任务越多的话提升效果越明显。

数据汇总开始
查询在线人数 耗时2秒
查询注册人数 耗时2秒
查询订单总额 耗时3秒
查询支出总额 耗时3秒
获取汇总数据结束,result = Test.Result(onlineUser=10, registered=10086, orderAmount=2000, outlayAmount=1000)
总耗时 = 3079毫秒

总结

1.parallelStream是异步编程的好帮手,在使用过程中一定要注意线程安全的问题。

2.以上这种方式只能用在没有事务的业务中,因为在多线程中,事务是不共享的。


以上所述就是小编给大家介绍的《java8的parallelStream提升数倍查询效率》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

信息架构

信息架构

[美] 路易斯·罗森菲尔德、[美] 彼得·莫尔维莱、[美] 豪尔赫·阿朗戈 / 樊旺斌、师蓉 / 电子工业出版社 / 2016-5-1 / 128.00元

本书的前三个版本都是信息架构领域的开山著作。其中描述了信息组织的普遍和永恒原则,这一原则也适用于不断增长的移动世界。在第4版中,作者运用大量最新的插图和例子为这些原则提供了当前实践中的情境,验证了那些与技术和供应商无关的工具,以及那些经受住时间考验的技术。一起来看看 《信息架构》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试