我们经常会有这种需求,比如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;
}