成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SpringBoot項目中異步調用接口方式知多少?

開發 前端
CompletableFuture提供了非常強大的異步編程方法,可同步,可異步,可編排任務執行,異步通過回調的方式執行。該對象很多的一些方法與前端JavaScript中的Promise對象有點相像。


環境:springboot2.5.12

經常會遇到在項目中調用第三方接口的情景,你是如何調用的呢?同步?異步?

場景:

假設下單業務流程如下步驟:

1、查詢用戶信息。

2、查詢庫存信息。

3、查詢活動信息(折扣)。

1、同步順序調用

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() ;
}

調用結果:

圖片圖片

接口一個一個調用,非常耗時。

2、多線程(Callable+Future)

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的錯誤。

3、線程池(Callable+Future)防止內存溢出風險

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的方式有一個問題就是只能一個一個的取值,只有當前的返回數據了后才會繼續往下執行。如果有其它的任務執行完,那沒有輪到它也必須等待。

4、CompletionService(異步任務與使用已完成任務的結果分離),submit提交任務,take獲取已經完成的任務,不用按照submit的順序獲取結果。

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方法會阻塞。

5、CompletableFuture(異步任務編排),JDK1.8

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對象有點相像。

完畢!!!


責任編輯:武曉燕 來源: Spring全家桶實戰案例源碼
相關推薦

2021-03-19 10:14:28

SpringBoot項目異步調用

2021-03-29 09:26:44

SpringBoot異步調用@Async

2021-12-10 07:47:30

Javascript異步編程

2022-09-27 12:01:56

Spring異步調用方式

2010-03-01 14:01:50

WCF服務異步調用

2009-10-20 16:48:30

C#委托

2024-10-15 10:28:43

2018-12-12 15:01:22

開源存儲 軟件

2009-11-09 10:50:30

WCF異步調用

2009-12-21 14:10:26

WCF異步調用

2021-03-30 10:46:42

SpringBoot計數器漏桶算法

2022-09-28 14:54:07

Spring注解方式線程池

2009-11-06 15:54:15

WCF異步調用

2009-07-01 13:58:00

JavaScript異

2009-12-07 14:35:42

WCF異步調用

2010-01-11 17:24:19

VB.NET異步調用

2011-03-02 08:57:22

jQueryJavaScript

2012-10-29 10:59:27

Windows 8

2009-12-07 14:26:47

WCF異步調用

2012-02-13 22:50:59

集群高可用
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日本欧美在线 | 亚洲一区 | 91一区二区 | 每日在线更新av | www.久久 | 亚洲视频不卡 | 91久久久久久久久久久 | 毛色毛片免费看 | 亚洲一区二区三区免费在线观看 | 久久久久久久久久久久久九 | 久久中文字幕av | 91精品国产91久久久久久吃药 | 成人黄色电影在线播放 | 日韩欧美一级片 | 日韩欧美三区 | 欧美激情精品久久久久久变态 | 欧美一级久久精品 | 成人三级网址 | 亚洲女人天堂成人av在线 | 福利网址 | 久久久久久久久毛片 | 久久精品国产免费看久久精品 | 超碰操 | av网站免费在线观看 | 国产一区二区三区四区在线观看 | 国产成在线观看免费视频 | 激情久久网| 永久www成人看片 | 美女网站视频免费黄 | 99视频免费播放 | 欧美性乱| 欧美一区2区三区4区公司二百 | 国产女人与拘做视频免费 | 在线观看视频你懂得 | 激情国产在线 | 日韩欧美网 | 国产一级视频免费播放 | 国产成人精品久久二区二区91 | 中文成人无字幕乱码精品 | 日本粉嫩一区二区三区视频 | 久久久男人的天堂 |