实际工作中遇到一个业务场景需要解决: 项目中需要调用外部查询服务,以验证客户某些提交数据是否满足条件。 外部服务提供方强势将查询服务封装成三个调用服务,并且需要轮训调用状态,如下图所示: 。
最近了解到FutureTask恰恰是为了解决这种业务场景的工具,随将手头代码重构,此处只贴出重构的后的部分代码:
public class OldClientValidateTask implements Callable {
Logger logger = LoggerFactory.getLogger(OldClientValidateTask.class);
private volatile boolean cannotQuitJob = true;
private boolean overtime = false;
/**
* 总等待超时时间
*/
private int totalWaitMinutes = 65;
/**
*间隔时间
*/
private int intvervalMinutes = 2;
@Override
public Object call() throws Exception {
if (StringUtils.isBlank(oldAcctIds)) return null;
OldClientValidateInvoker oldClientValidateInvoker = SpringContextHolder.getBean(OldClientValidateInvoker.class);
//发送给对方请求 第一个接口
String sendQueryResult = oldClientValidateInvoker.sendQuery(period, oldAcctIds);
if (StringUtils.isBlank(sendQueryResult)) {
logger.error("百度旧用户校验接口返回数据格式不正常" + sendQueryResult);
throw new ResultNotMatchException(ErrorCodeMessageBucket.ERROR_CODE_RESULT_NOT_MATCH);
}
//解析出requestId
Map<String, String> resultMap = (HashMap<String, String>) JsonMapper.fromJsonString(sendQueryResult, HashMap.class);
String requestId = resultMap.get("data");
if (requestId == null) return null;
//任务启动时间
final LocalDateTime startTime = LocalDateTime.now();
try {
while (cannotQuitJob) {
//如果超时 不再调用
if ((LocalDateTime.now().isAfter(startTime.plusMinutes(totalWaitMinutes)))) {
overtime = true;
logger.info("超时退出,超时时间:" + totalWaitMinutes);
break;
}
//第二个接口
boolean requestSucceed = oldClientValidateInvoker.checkStatus(requestId);
logger.info("请求调用是否成功: {}", requestSucceed);
if (requestSucceed) {
//调用第三个接口 返回真正数据
return fetchResult(oldClientValidateInvoker, requestId);
}
//如果没有执行完 那么就等待
if (cannotQuitJob) {
Thread.sleep(1000 * 60 * intvervalMinutes);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
调用方过程如下:
//创建异步调用任务
OldClientValidateTask oldClientValidateTask = new OldClientValidateTask();
FutureTask<List<Foo>> future = new FutureTask<List<Foo>>(oldClientValidateTask);
// 创建线程池(使用了预定义的配置)
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(future);
//查询返回结果 此处会一直等待,直到对方返回查询结果,竟然实现了异步转同步。
List<Foo> dbdSjClientRenewInfos = future.get();
此处为一个真实的场景。FutureTask在此发挥用处。