经常会遇到在项目中调用第三方接口的情景,你是如何调用的呢?同步?异步?
场景:
假设下单业务流程如下步骤:
1、查询用户信息。
2、查询库存信息。
3、查询活动信息(折扣)。
- public boolean createOrder() {
- long start = System.currentTimeMillis() ;
- String userResult = restTemplate.getForObject("http://localhost:8080/users/{1}", String.class, new Object[] {1}) ;
- String storageResult = restTemplate.getForObject("http://localhost:8080/storage/{1}", String.class, new Object[] {1}) ;
- String discountResult = restTemplate.getForObject("http://localhost:8080/discount/{1}", String.class, new Object[] {1}) ;
- // 这里合并请求结果处理
- System.out.println(Arrays.toString(new String[] {userResult, storageResult, discountResult})) ;
- System.out.println("传统方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;
- return true ;
- }
- @GetMapping("/create")
- public Object create() {
- return os.createOrder() ;
- }
调用结果:
接口一个一个调用,非常耗时。
- public boolean createOrder2() {
- long start = System.currentTimeMillis() ;
- Callable<String> userCallable = () -> {
- return restTemplate.getForObject("http://localhost:8080/users/{1}", String.class, new Object[] {1}) ;
- } ;
- Callable<String> storageCallable = () -> {
- return restTemplate.getForObject("http://localhost:8080/storage/{1}", String.class, new Object[] {1}) ;
- } ;
- Callable<String> discountCallable = () -> {
- return restTemplate.getForObject("http://localhost:8080/discount/{1}", String.class, new Object[] {1}) ;
- } ;
- FutureTask<String> userTask = new FutureTask<>(userCallable) ;
- FutureTask<String> storageTask = new FutureTask<>(storageCallable) ;
- FutureTask<String> discountTask = new FutureTask<>(discountCallable) ;
- new Thread(userTask).start() ;
- new Thread(storageTask).start() ;
- new Thread(discountTask).start() ;
- try {
- String userResult = userTask.get() ;
- String storageResult = storageTask.get() ;
- String discountResult = discountTask.get() ;
- // 这里合并请求结果处理
- System.out.println(Arrays.toString(new String[] {userResult, storageResult, discountResult})) ;
- } catch (InterruptedException | ExecutionException e) {
- e.printStackTrace();
- }
- System.out.println("多线程方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;
- return true ;
- }
调用结果:
这次耗时少了,性能明显提升了。但在项目中我们一般是禁止直接创建线程的,如果这是个高并发的接口,那么我们的程序很可能出现OOM的错误。
- ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000)) ;
- public boolean createOrder3() {
- long start = System.currentTimeMillis() ;
- List<Future<String>> results = new ArrayList<>(3) ;
- results.add(pool.submit(() -> {
- return restTemplate.getForObject("http://localhost:8080/users/{1}", String.class, new Object[] {1}) ;
- })) ;
- results.add(pool.submit(() -> {
- return restTemplate.getForObject("http://localhost:8080/storage/{1}", String.class, new Object[] {1}) ;
- })) ;
- results.add(pool.submit(() -> {
- return restTemplate.getForObject("http://localhost:8080/discount/{1}", String.class, new Object[] {1}) ;
- })) ;
- for (int i = 0, size = results.size(); i < size; i++) {
- try {
- System.out.println(results.get(i).get()) ;
- } catch (InterruptedException | ExecutionException e) {
- e.printStackTrace();
- }
- }
- System.out.println("线程池方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;
- return true ;
- }
调用结果:
耗时和上一个基本一致,通过Future的方式有一个问题就是只能一个一个的取值,只有当前的返回数据了后才会继续往下执行。如果有其它的任务执行完,那没有轮到它也必须等待。
- public boolean createOrder4() {
- long start = System.currentTimeMillis() ;
- CompletionService<String> cs = new ExecutorCompletionService<>(pool) ;
- cs.submit(() -> {
- return restTemplate.getForObject("http://localhost:8080/users/{1}", String.class, new Object[] {1}) ;
- }) ;
- cs.submit(() -> {
- return restTemplate.getForObject("http://localhost:8080/storage/{1}", String.class, new Object[] {1}) ;
- }) ;
- cs.submit(() -> {
- return restTemplate.getForObject("http://localhost:8080/discount/{1}", String.class, new Object[] {1}) ;
- }) ;
- for (int i = 2 ; i >=0; i--) {
- try {
- System.out.println(cs.take().get()) ;
- } catch (InterruptedException | ExecutionException e) {
- e.printStackTrace();
- }
- }
- System.out.println("CompletionService方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;
- return true ;
- }
调用结果:
通过CompletionService方式不管任务添加的顺序是什么,只要通过take方法就能获取执行完的结果,如果没有任务执行完,take方法会阻塞。
- public boolean createOrder5() {
- long start = System.currentTimeMillis() ;
- CompletableFuture<String> userFuture = CompletableFuture.supplyAsync(() -> {
- return restTemplate.getForObject("http://localhost:8080/users/{1}", String.class, new Object[] {1}) ;
- }) ;
- CompletableFuture<String> storageFuture = CompletableFuture.supplyAsync(() -> {
- return restTemplate.getForObject("http://localhost:8080/storage/{1}", String.class, new Object[] {1}) ;
- }) ;
- CompletableFuture<String> discountFuture = CompletableFuture.supplyAsync(() -> {
- return restTemplate.getForObject("http://localhost:8080/discount/{1}", String.class, new Object[] {1});
- }) ;
- CompletableFuture<List<String>> result = CompletableFuture
- .allOf(userFuture, storageFuture, discountFuture)
- .thenApply((Void) -> {
- List<String> datas = new ArrayList<>() ;
- try {
- datas.add(userFuture.get()) ;
- datas.add(storageFuture.get()) ;
- datas.add(discountFuture.get()) ;
- } catch (InterruptedException | ExecutionException e) {
- e.printStackTrace();
- }
- return datas ;
- }).exceptionally(e -> {
- e.printStackTrace() ;
- return null ;
- }) ;
- try {
- System.out.println(result.get()) ;
- } catch (InterruptedException | ExecutionException e1) {
- e1.printStackTrace();
- }
- System.out.println("CompletableFuture方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;
- return true ;
- }
调用结果:
CompletableFuture提供了非常强大的异步编程方法,可同步,可异步,可编排任务执行,异步通过回调的方式执行。该对象很多的一些方法与前端JavaScript中的Promise对象有点相像。
在这篇文章中,我将与你分享我从其他数据科学家以及我自己过去几年的经验中学到...
如今,越来越多的企业依靠人工智能技术为运营业务提供帮助。这项技术非常具有建...
为什么要写这类文章 作为一个程序员,代码能力毋庸置疑是非常非常重要的,就像现...
随着前端工程日益复杂,某些业务或者工具库通常涉及到很多个仓库,那么时间一长...
大家好,我是站长 polarisxu。 2021 年 3 月 1 日,RedMonk 发布了 2021 年 1 月...
介绍 图表是数据的图形表示,用于使数据集更易于阅读,并且易于区分各部分。虽然...
一、前言 前几天一个朋友找我,说有一个 数据接口开发 能够页面展示的小项目,能...
本文转载自微信公众号「crossoverJie」,作者crossoverJie。转载本文请联系cross...
众所周知,人类在预测未来(尤其是从长远来看)方面很差。但是,它仍然是有用的练...
对于许多组织来说,在冠状病毒疫情持续蔓延期间,云计算和边缘计算对维持其业务...