需求
項目使用springboot,有一個場景需要先從本地查詢所有數據,然后再調用第三方接口填充其他字段,每次調用第三方接口都需要本地數據的字段作為查詢條件。廠商提供的接口只能單個查詢,所以只能遍歷從本地查詢的數據然后挨個調用接口,這樣響應時間實在慢且效率太低。
那就想辦法優化唄,第一想法肯定是啟用多線程,讓每一條從本地數據庫查詢的記錄可以並行調用第三方接口。
首先新建一個線程任務類來調用第三方接口並填充數據,用spring的@Async注解實現異步調用,偽代碼如下:
-
@Component
-
public
class AsyncTask {
-
-
-
/**
-
* 異步調用第三方接口查詢
-
*/
-
@Async
-
public void queryTask(Entity entity){
-
Data data = doPost();
-
entity.setData(data);
-
}
-
-
}
Service層循環調用
-
public
class Service {
-
-
@Autowired
-
private AsyncTask asyncTask;
-
@Autowired
-
private EntityMapper mapper;
-
-
public List<Entity> queryData(){
-
-
List<Entity> list = mapper.selectAll();
-
for(Entity entity:list){
-
asyncTask.queryTask(entity);
-
}
-
-
return list;
-
}
-
}
這樣就實現了異步請求接口,效率上提升了很多。但是,由於異步調用的原因,數據還沒填充完就會返回,這顯然不是我們想要的效果。我們必須等待AsyncTask中的所有線程結束后,再返回當前調用線程任務的方法。於是就想到了JDK1.5版本后提供的計數器CountDownLatch(至於CountDownLatch的用法本文不闡述,只是第一次使用記錄一下,有錯誤的地方還希望大家給建議)。
思路:
在Service層的方法中實例化CountDownLatch並且制定線程個數,線程個數就是從本地數據庫查詢的list的長度,並且傳入線程任務中,每個線程執行完畢就調用countDown()方法。最后在Service層中調用await()方法。這樣在線程計數為零之前,Service的線程就會一直等待。
Service:
-
public
class Service {
-
-
@Autowired
-
private AsyncTask asyncTask;
-
@Autowired
-
private EntityMapper mapper;
-
-
public List<Entity> queryData(){
-
-
List<Entity> list = mapper.selectAll();
-
CountDownLatch latch =
new CountDownLatch(list.size());
-
for(Entity entity:list){
-
asyncTask.queryTask(entity,latch);
-
}
-
latch.await();
-
return list;
-
}
-
}
AsyncTask:
-
@Component
-
public
class AsyncTask {
-
-
-
/**
-
* 異步調用第三方接口查詢
-
*/
-
@Async
-
public void queryTask(Entity entity,CountDownLatch latch){
-
Data data = doPost();
-
entity.setData(data);
-
latch.countDown();
-
}
-
-
}
至此問題解決。