java - 使用 Spring 4.0 的新 ListenableFuture 和回调 - 奇怪的结果

标签 java spring threadpool java.util.concurrent

我有一个网络应用程序,它接受一组 ID,一次为每个 ID 查询一个外部网络服务,并在每个结果通过 STOMP 代理到达 WebSocket 客户端时发布。我可以使用简单的 Futures 让它工作,但我正在尝试使用 Spring 4 的新 ListenableFutures 并提供回调。

工作代码使用在我的根配置中定义的 ThreadPoolTask​​Executor。我有一个名为“SosQuery”的类,它有一个名为“test”的方法,该方法用@Async 注释并返回一个AsyncResult。这是从根上下文服务类调用的我的工作代码:

@Override
    public void test(String[] oids) throws Exception {
        List<Future<String>> futures = new ArrayList<Future<String>>();

        for (String oid : oids) {
            futures.add(sosQuery.test(oid));
        }

        while (!futures.isEmpty()) {
            List<Future<String>> done = new ArrayList<Future<String>>();
            for (Future<String> future : futures) {
                if (future.isDone()) {
                    messagingTemplate.convertAndSendToUser("me", "/queue/observation", future.get());
                    done.add(future);
                }
            }
            futures.removeAll(done);
        }
    }

这工作正常,我看到响应到达了我的客户端。我修改了使用 @Async 注释定义的 SosQuery 方法以简单地返回“String”,并在我的根配置中创建了一个 SimpleAsyncTaskExecutor。这是使用 ListenableFuture 的修改方法:

 @Override
    public void test(String[] oids) throws Exception {
        for (final String oid : oids) {
              ListenableFuture<String> task = asyncTaskExecutor.submitListenable(new Callable<String>(){
                @Override
                public String call() throws Exception {
                    String result = sosQuery.test(oid);
                    logger.debug("result for sosQuery: " + result);
                    return result;
                }
            });

            task.addCallback(new ListenableFutureCallback<String>() {

                @Override
                public void onSuccess(String result){
                    if (result == null){
                        result = "ITS NULL";
                    }
                    messagingTemplate.convertAndSendToUser("me", "/queue/observation", result);
                }

                @Override
                public void onFailure(Throwable t){
                    logger.error("Error executing callback.", t);
                }
            });
        }
    }

我看到了奇怪的行为...当我在 Debug模式下部署时,我可以看到 call() 方法正在执行并且结果是从 SosQuery 类正确构建的,但是我的记录器语句从未出现在日志。紧接着,onSuccess 方法执行,但结果 String 为 null。

永远不会调用 onFailure 方法,并且日志中绝对没有任何区别。使用 ListableFutures 的文档很少并且与 AsyncRestTemplate 紧密耦合,但几乎没有用于创建您自己的任务的文档。有人知道我可能做错了什么吗?

最佳答案

您应该在 SosQuery.test 方法中删除 @Async。

ListenableFuture<String> task = asyncTaskExecutor.submitListenable(new Callable<String>(){
                @Override
                public String call() throws Exception {
                    String result = sosQuery.test(oid);
                    logger.debug("result for sosQuery: " + result);
                    return result;
                }
            });

这里 call() 方法中的内容已经在单独的线程中调用。如果你在测试方法中有@Async。然后它会创建另一个线程并立即返回(这就是为什么你在测试方法完成之前立即得到响应)

还有来自 的另一条重要说明 Doc **

    This implementation does not reuse threads! Consider a thread-pooling TaskExecutor 
implementation instead, in particular for executing a large number of short-lived tasks.

关于java - 使用 Spring 4.0 的新 ListenableFuture 和回调 - 奇怪的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23681822/

相关文章:

Java在对象构造函数中启动线程池

java - 替换选择排序

java - 使用cascade={CascadeType.TYPE_NAME}的目的是什么

java - JAXB XmlElementRef 查找整个类路径

java - Spring 参数太长

Python - 从线程池调用 Linux 命令不起作用

Java ThreadPoolExecutor 策略, 'Direct Handoff' 带队列?

java - Weblogic 中用于集群计时器的单例服务

java - 无法使用 Java 在 Amazon S3 中上传文件

java - EditText 不存储输入的第一个值,然后在添加新值时存储先前的值