查询Guava ListenableFuture

时间:2014-02-07 02:40:26

标签: java concurrency guava future

我正在编写一个调用一些外部服务的服务。我使用期货来表示所有这些外部服务电话的结果。我使用Guava库提供的Futures.successfulAsList()方法将所有期货合并到一个未来。

这是我的代码

List<ListenableFuture<List<T>>> futureList = new ArrayList<>();

for(int id: shardIds) {
    ListeningExecutorService service =
          (ListeningExecutorService) _shardMgr.getExecutorService(id);
    SelectTask task = new SelectTask(_shardMgr.getReadHandle(id), sql, mapper);


    ListenableFuture<List<T>> future = service.submit(task);
    //Add Callback
    Futures.addCallback(future, new ErrorCallBack(task),
            Executors.newFixedThreadPool(1));
    futureList.add(future);
}

ListenableFuture<List<List<T>>> combinedFuture =
        Futures.successfulAsList(futureList);
int timeout = _dbTimeout.get();
List<T> selectResult = new ArrayList<T>();

try {
    List<List<T>> result = combinedFuture.get(timeout, TimeUnit.MILLISECONDS);
    for(List<T> sublist: result) {
        for(T t : sublist) {
            //TODO: Do we want to put a cap on how many results we return here?
            //I think we should
            selectResult.add(t);
        }
    }
}
catch(Exception ex) {
    log.error("******************* Exception in parallelSelect ",ex);
    throw new RuntimeException("Error in parallelSelect");
}

当我的未来之一(外部服务调用)失败时,调用了ErrorCallBack的onFailure(),但我仍然超过了combinedFuture.get(timeout,TimeUnit.MILLISECONDS);并且我在迭代结果的同时获得(T t:sublist)...的NullPointerException。

我希望当一个外部服务调用失败时,我不应该超过combinedFuture.get()

我做错了吗?我甚至试图从ErrorCallBack的onFailure方法中抛出Exception。

这是ErrorCallBack的实现

private class ErrorCallBack<T> implements FutureCallback<List<T>>  {
    private final SelectTask _task;

    public ErrorCallBack(SelectTask task) {
        _task = task;
    }

    @Override
    public void onFailure(Throwable t) {
        log.error("ErrorCallBack:onFailure(). Enter");
        DBErrorType type = DBErrorType.UNKNOWN;
        try {
            log.error("ErrorCallBack:onFailure(). Exception ",t);
            if(t instanceof InterruptedException || t instanceof CancellationException) {
                type = DBErrorType.UNKNOWN;
            } else if ( t instanceof SQLException || t.getCause() instanceof SQLException) {
                type = DBErrorType.SQL_SYNTAX_ERROR;
            } else if ( t instanceof MySQLSyntaxErrorException || t.getCause() instanceof MySQLSyntaxErrorException) {
                type = DBErrorType.SQL_SYNTAX_ERROR;
            } else if ( t instanceof ExecutionException) {
                type = DBErrorType.SQL_SYNTAX_ERROR;
            } else if (t instanceof TimeoutException) {
                type = DBErrorType.NETWORK_ERROR;
            } else {
                type = DBErrorType.UNKNOWN;
            }
            ShardHandle handle = _task.getShardHandle();
            _shardMgr.reportException(handle, type);
            DBException exception = new DBException(handle.getShardInfo(), type, ErrorSeverity.CRITICAL, t);
            _alertModule.handleAlert(exception.getAlertContext());
        } catch( Exception ex) {
        }
    }

    @Override
    public void onSuccess(List<T> result) {}
}

1 个答案:

答案 0 :(得分:4)

  

我希望当一个外部服务调用失败时,我不应该超过combinedFuture.get()

嗯,不,因为你正在调用Futures.succcessfulAsList(),正如其名称所暗示的那样,returns the results of the successful Futures(对于那些失败的人来说是null)。对于您想要的行为,您应该调用Futures.allAsList(),如果其任何组件发生故障,则会Future失败。

由于您未检查结果中的空值,因此您将获得NPE。