java8 每秒循环次数_java8中parallelStream提升数倍查询效率是怎样实现的,来看看这篇文章...

062792433e31085614f585bd1bba9a4b.png

作者:我恰芙蓉王

业务场景

在很多项目中,都有类似数据汇总的业务场景,查询今日注册会员数,在线会员数,订单总金额,支出总金额等。。。这些业务通常都不是存在同一张表中,我们需要依次查询出来然后封装成所需要的对象返回给前端。那么在此过程中,就可以把这个接口中“大任务”拆分成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毫秒

异步执行

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

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

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

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

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

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

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

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

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

@org.junit.Test

public void collect() {

System.out.println("数据汇总开始");

long startTime = System.currentTimeMillis();

Result result = new Result();

List taskList = new ArrayList() {

{

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.以上这种方式只能用在没有事务的业务中,因为在多线程中,事务是不共享的。

最后

私信回复 资料 领取一线大厂Java面试题总结+阿里巴巴泰山手册+各知识点学习思维导+一份300页pdf文档的Java核心知识点总结!

这些资料的内容都是面试时面试官必问的知识点,篇章包括了很多知识点,其中包括了有基础知识、Java集合、JVM、多线程并发、spring原理、微服务、Netty 与RPC 、Kafka、日记、设计模式、Java算法、数据库、Zookeeper、分布式缓存、数据结构等等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值