我們經常會有這種需求,比如APP首頁,需要同時加載20多個接口,你怎么做?一個個按順序調用接口嗎?如果網絡通暢還好,如果網絡不好,你可能會讓首頁加載幾分鐘,用戶體驗肯定不好,那么我們就需要使用多線程來做。那假設其中有幾個接口需要都執行完了,你才能繼續執行后面的代碼,怎么做?那這時候就需要?ExecutorService中的? <T> Future<T> submit(Callable<T> task);方法了。
1.工具類FutureUtils.java
/*** */
package com.figo.html5.future;import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 多線程執行任務 .* * @author figo . 20190711 add .*/
public class FutureUtils{/*** SUCCESS .*/public static final String SUCCESS="1";/*** * @param tasks .* @return .*/public static boolean useFuture(List<BaseTask> tasks) {long start = System.currentTimeMillis();// 固定線程池線程個數ExecutorService executor = Executors.newFixedThreadPool(tasks.size());for(BaseTask task:tasks){executor.submit(task);}executor.shutdown();while (true) {if (executor.isTerminated()) {long end = System.currentTimeMillis();System.out.println("所有任務執行完畢,總耗時(毫秒):" + (end - start));return true;}try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}
2.BaseTask.java任務基類
package com.figo.html5.future;import java.util.List;
import java.util.concurrent.Callable;/** * BaseTask.java .* * @author figo.zhu .* @serial .* @param <T> .* @since 2019年7月11日 下午3:37:57 .*/
public abstract class BaseTask<T> implements Callable<T> {/*** result list .*/List<T> listResult;/*** result .*/T result;/*** * @return .*/public List<T> getListResult() {return listResult;}/*** * @param listResult .*/public void setListResult(List<T> listResult) {this.listResult = listResult;}/*** * @return .*/public T getResult() {return result;}/*** * @param result .*/public void setResult(T result) {this.result = result;}}
3.其中一個任務,查詢商戶開通的支付銀行列表?QueryMerBankConfigTask.java,其他相似
/** * QueryMerBankConfigTask.java* * @author sun.jun* @serial * @since 2019年7月11日 下午3:47:31*/
package com.figo.html5.future;import java.util.List;import com.figo.service.impl.APBusServiceImpl;
import com.figo.util.log.MonitorLogger;/** * QueryMerBankConfigTask.java .* * @author figo.zhu .* @serial * @since 2019年7月11日 下午3:47:31 .*/
public class QueryMerBankConfigTask extends BaseTask<String> {/*** 日志.*/private MonitorLogger logger = MonitorLogger.getLogger(QueryMerBankConfigTask.class);/*** merId .*/String merId;/*** tranType .*/String tranType;/*** * @param merId .* @param tranType .*/public QueryMerBankConfigTask(String merId,String tranType){this.merId=merId;this.tranType=tranType;}/*** call .* @return String .* @exception Exception .*/@Overridepublic String call() throws Exception {try {long start = System.currentTimeMillis();List<String> bankInstNoList = new APBusServiceImpl().getPayMode(merId, tranType);this.listResult=bankInstNoList;long end = System.currentTimeMillis();System.out.println("getPayMode任務執行完畢,耗時(毫秒):" + (end - start));logger.info(merId+","+tranType+"配置的支付機構:"+bankInstNoList);return "1";} catch (Exception e) {logger.error("QueryMerBankConfigTask Exception:" + e.getStackTrace());return "0";}}}
4.調用(偽代碼,自行調通)
boolean isFinished=FutureUtils.useFuture(tasks);//所有任務結束,獲取支付結果if(isFinished){bankInstNoListFor0001=queryMerBankConfigTaskFor0001!=null?queryMerBankConfigTaskFor0001.getListResult():bankInstNoListFor0001;bankInstNoListFor0004=queryMerBankConfigTaskFor0004!=null?queryMerBankConfigTaskFor0004.getListResult():bankInstNoListFor0004;bankInstNoListFor0005=queryMerBankConfigTaskFor0005!=null?queryMerBankConfigTaskFor0005.getListResult():bankInstNoListFor0005;bankInstNoListFor0008=queryMerBankConfigTaskFor0008!=null?queryMerBankConfigTaskFor0008.getListResult():bankInstNoListFor0008;whetherSupportItemFlag=queryItemFlagTask!=null?queryItemFlagTask.getResult():false;fcBankInstNoList =queryAllForeignCardBanksTask!=null?queryAllForeignCardBanksTask.getListResult():fcBankInstNoList;}
關鍵是調用executor.isTerminated()來判斷所有線程是否已經執行完成。
if (executor.isTerminated()) {
?? ??? ??? ??? ?long end = System.currentTimeMillis();
?? ??? ??? ??? ?System.out.println("所有任務執行完畢,總耗時(毫秒):" + (end - start));
?? ??? ??? ??? ?return true;
?? ??? ??? ?}