所谓高并发,不仅仅是高层次的架构规划,还需要开发者在具体的每一行代码、每一个细节上都去关注业务发展。同时,更重要的是要有内衬。在性能面前,我们要有自己的工匠精神,不能在任何一行代码上妥协!今天给大家分享一个小技巧,如何降低业务开发中的界面响应时间,这也是大家日常开发中的常见问题,即如何提高程序的并行计算能力?本文主要包含以下内容:顺序执行很慢线程池+Future并行计算使用Java8的CompletableFuture使用Guava的ListenableFuture这篇文章代码内容比较多,大家可以自己收藏验证范~顺序执行很多次,当我们开发一个接口,需要调用多个方法,然后将每个方法返回的数据组装起来返回给前端,比如这样:大家可以看到我这里调用了4个方法,每个方法都是为了模拟实际耗时,返回一个字符串,延迟100ms:可以想象我们的接口响应时间会超过400ms,多次执行400ms多一点:耗时:403ms耗时:409ms时间:406ms这是顺序执行。可能你觉得很Low,但是想想你自己的代码,不是经常这样吗?线程池+Future并行计算顺序执行真的很慢,所以需要并行执行,也就是同时调用,熟悉Java多线程的都知道这四种方法。每个方法开一个线程异步执行就可以了。所有的方法执行完之后,就可以得到独立线程执行的结果,然后再进行组装。但是每次调用需要创建四个线程,线程的创建和销毁需要开销,所以我们有了池化技术。线程池、数据库连接池等都使用池化技术:预先初始生成和创建线程,需要调用时使用。线程完成工作后,又回到空闲状态,等待下一个任务的到来。避免了线程的频繁创建和销毁,提高了程序的响应性能。所以我们在做并行计算的时候,一定要充分利用线程池的相关技术。线程池的技术在我的另一篇文章中单独提到。不了解的同学可以初步了解。面试也是必须的。一:Java线程池基础知识直接上代码:线程池+Future多跑几次看输出响应时间:耗时:108ms耗时:105ms耗时:105ms效果明显吗?直接相当于一个方法在实际开发中,如果你的某个接口在压测后耗时100ms左右(一般正规公司对接口性能要求不会超过100ms),那么通过线程池+Future并行计算的方式,并且可以瞬间提升你的界面性能,再也不用担心压测不通过了。有时候测试同学跟你说,接口压测是不是很尴尬?那是对你专业水平的极大否定~Java8的CompletableFutureFuture是java.util.concurrent契约传递中的一个接口类,用来表示一个线程异步执行后的结果,核心方法有以下几个:Future.get():Block调用线程直到计算结果返回Future.isDone():判断线程是否执行完毕Future.cancel():取消当前线程的执行我们知道是的,Future.get()是一个阻塞调用。如果想得到线程执行的结果,必须调用Future.get()阻塞或者while(Future.isDone())轮询。这种方法叫做“主动拉(pull)”。现在流行响应式编程,也就是“主动推送(push)”的方式。当线程完成执行时,告诉我。Java8设计了CompletableFuture这样的类。下面看看如何使用CompletableFuture开发前面的代码:CompletableFuture并行计算这里可以看到实现方式和Future没什么区别,但是CompletableFuture提供了很多方便的方法,比如代码里面的allOf和thenApplyAsync可以结合多个CompletableFuture合并为一个CompletableFuture,最后调用join方法阻塞得到结果。多次调用该接口耗时如下:耗时:110ms耗时:108ms耗时:105msCompletableFuture类中有很多方法(50+),大家可以使用。与Future不同的是,只能使用几个方法,这也是Java自带的库对Future的一个增强。这只是CompletableFuture用法的简要演示。在实际开发中,需要根据不同的场景选择不同的方式。API在此不做详细介绍。Guava的ListenableFuture总是有一些牛逼的公司和牛逼的人想出一些牛逼的开源组件,比官方的工具类好很多。同样,Google开源的Guava中的ListenableFuture接口,兼容java自带的Future接口,进一步扩展,提供静态工具类Futures。对于上面的代码,我们看一下如何使用ListenableFuture来实现(与之前不同,Guava需要重新包装线程池):执行三个请求的耗时:耗时:103ms耗时:101ms耗时:103msFinally以上是如何让自己的接口并行计算的三种实现方法。是日常开发中常用的一个小技巧。这三种方法的具体区别就不多解释了。其实还需要继续开发Go才能使用,多查看相关源码和资料,只有真正使用过,才能体会到!
