
我們先來設想一個場景。
有一個 http 的接口 A,該接口内部實際上是由另外三個接口 B、C、D 傳回結果的組合,這三個接口不存在互相依賴。我們一般的寫法就是 B、C、D 同步順序執行,依次拿到結果後組裝在一起。那麼假如這三個接口分别耗時 2 秒,那麼 A 接口就要耗時 6 秒。如果可以讓 B、C、D 同時執行的話,那麼 A 接口理論上隻要耗時 2 秒。
當然實際情況肯定複雜的多,如果一個接口内部存在不互相依賴的耗時調用的話,那麼我們可以做這樣的合并,響應時間上的減少還是非常明顯的。整個接口的響應時間取決于最長的那個内部接口。
那麼我們來看看在 Java 中有哪些方法可以達到這樣的目的。認真思考下你會發現,如果要并行處理的話,在 Java 中隻能用多線程來做。實際情況中每個線程處理完的時間肯定不一樣,那麼如何讓線程先處理完的停下來等最後那個處理完的呢。如果經常用多線程的小夥伴肯定能想到 CountDownLatch 工具類。當然也有直接簡單暴力的方法,在空循環裡輪詢每個線程是否執行完,但是這樣做肯定不優雅。
那下面就直接上代碼了: 假設有個學生服務提供查詢學生名字,年齡和家庭資訊,每個服務之間沒有互相依賴。 我們就簡單模拟下來擷取學生資訊的一個接口。
正常方法
@RequestMapping("/getStudentInfo")
public Object getStudentInfo() {
long start = System.currentTimeMillis();
Map resultMap = new HashMap<>(10);
try {
resultMap.put("studentName", studentService.getStudentName());
resultMap.put("studentAge", studentService.getSutdentAge());
resultMap.put("studentFamilyInfo", studentService.getSutdentFamilyInfo());
} catch (Exception e) {
resultMap.put("errMsg", e.getMessage());
}
resultMap.put("total cost", System.currentTimeMillis() - start);
return resultMap;
順序同步執行,耗時 6 秒。
1. Future
@RequestMapping("/getStudentInfoWithFuture")
public Object testWhitCallable() {
CountDownLatch countDownLatch = new CountDownLatch(3);
Future futureStudentName = es.submit(() -> {
Object studentName = studentService.getStudentName();
countDownLatch.countDown();
return studentName;
});
Future futureStudentAge = es.submit(() -> {
Object studentAge = studentService.getSutdentAge();
return studentAge;
Future futureStudentFamilyInfo = es.submit(() -> {
Object studentFamilyInfo = studentService.getSutdentFamilyInfo();
return studentFamilyInfo;
//同步等待所有線程執行完之後再繼續
countDownLatch.await();
resultMap.put("studentName", futureStudentName.get());
resultMap.put("studentAge", futureStudentAge.get());
resultMap.put("studentFamilyInfo", futureStudentFamilyInfo.get());
2.RxJava
@RequestMapping("/getStudentInfoWithRxJava")
public Object testWithRxJava() {
CountDownLatch countDownLatch = new CountDownLatch(1);
Observable studentNameObservable = Observable.create(observableEmitter -> {
observableEmitter.onComplete();
}).subscribeOn(Schedulers.io());
Observable studentAgeObservable = Observable.create(observableEmitter -> {
Observable familyInfoObservable = Observable.create(observableEmitter -> {
//建立一個下遊 Observer
Observer observer = new Observer() {
@Override
public void onSubscribe(Disposable d) {
public void onNext(Object o) {
public void onError(Throwable e) {
public void onComplete() {
//因為後面用了 merge 操作符,是以會合并後發射,那麼隻要 countdown 一次就行了。
};
//建立連接配接,
Observable.merge(studentNameObservable, studentAgeObservable, familyInfoObservable).subscribe(observer);
//等待異步線程完成
對于 RxJava 我不熟,我也是臨時學習的,不知道這種寫法是不是最佳的。
3.CompletableFutures
@RequestMapping("/getStudentInfoWithCompletableFuture")
public Object getStudentInfoWithCompletableFuture() {
CompletableFuture completableFutureStudentName = CompletableFuture.supplyAsync(() -> {
return studentService.getStudentName();
} catch (InterruptedException e) {
e.printStackTrace();
return null;
CompletableFuture completableFutureSutdentAge = CompletableFuture.supplyAsync(() -> {
return studentService.getSutdentAge();
CompletableFuture completableFutureFamilyInfo = CompletableFuture.supplyAsync(() -> {
return studentService.getSutdentFamilyInfo();
CompletableFuture.allOf(completableFutureStudentName, completableFutureSutdentAge, completableFutureFamilyInfo).join();
resultMap.put("studentName", completableFutureStudentName.get());
resultMap.put("studentAge", completableFutureSutdentAge.get());
resultMap.put("studentFamilyInfo", completableFutureFamilyInfo.get());
自帶最後的同步等待,不需要 CountDownLatch。CompletableFuture 還有很多其他好用的方法。
有興趣的可以自己來實驗下。 github 項目位址 reactive-programming-sample。
Java程式員如何學習才能快速入門并精通呢?
當真正開始學習的時候難免不知道從哪入手,導緻效率低下影響繼續學習的信心。
但最重要的是不知道哪些技術需要重點掌握,學習時頻繁踩坑,最終浪費大量時間,是以有一套實用的視訊課程用來跟着學習是非常有必要的。
為了讓學習變得輕松、高效,今天給大家免費分享一套阿裡架構師傳授的一套教學資源。幫助大家在成為架構師的道路上披荊斬棘。這套視訊課程詳細講解了(Spring,MyBatis,Netty源碼分析,高并發、高性能、分布式、微服務架構的原理,JVM性能優化、分布式架構)等這些成為架構師必備的内容!而且還把架構需要用到的各種程式進行了打包,根據基礎視訊可以讓你輕松搭建分布式架構環境,像在企業生産環境一樣進行學習和實踐。
如果想提升自己的,看看上圖大綱能知道你現在還處于什麼階段要向那些方面發展?
同時小編已将上圖知識大綱裡面的内容打包好了......想要資料的朋友,可以直接加群960439918擷取免費架構資料(包括高可用,高并發,spring源碼,mybatis源碼,JVM,大資料,Netty等多個技術知識的架構視訊資料和各種電子書籍閱讀)
加入群聊【java進階架構交流群】