【问题标题】:A strange issue when using Java's Future/Callable使用 Java 的 Future/Callable 时的一个奇怪问题
【发布时间】:2015-01-16 21:34:35
【问题描述】:

我相信我理解 Future/Callable 的工作原理。就像下面的代码(第 2 节)一样,cacheLoader1 和 cacheLoader2 是 Callable 实现的两个实例,它的 call() 方法是加载一个缓存

@Override
public Cache call() throws Exception {
  cache.loadCache();
  return cache;
}

我打算使用两个线程来运行任务并合并返回的缓存。我了解 future#get() 将阻塞,直到相应的线程完成。但是,我遇到的问题是它永远不会返回。我注释掉了 Future#get() 的单行,它继续进行。

我查看了 cache#loadCache() 中的代码,发现它尝试从 DB 表中检索数据,例如 service.getData(),在它下面调用 DAO,而 DAO 又使用 Spring 的 getSqlMapClientTemplate 和 iBatis SQL。如果我恢复注释的 Future#get,DAO 将永远不会返回。

List<Future<Cache>> list = new ArrayList<Future<Cache>>();
Future<Cache> f = es.submit(cacheLoader1);
list.add(f);
f = es.submit(cacheLoader2);
list.add(f);

for(Future<Cache> future: list){
  logger.debug("done with {}",future.get());
}

我很难理解可能出了什么问题。有什么帮助吗?是因为调用方法中的 throws Exception 子句吗?

附言进一步澄清:

ExecutorService es = Executors.newFixedThreadPool(2);
class CacheLoader implements Callable<Cache>{
  ....
  @Override
  public Cache call() throws Exception {
    cache.loadCache();
    return cache;
  }
}
CacheLoader cacheLoader1, cacheLoader2;

更新

我似乎找到了根本原因,但需要建议最好的解决方案是什么。首先我很抱歉,早期的信息不足以让人们查明问题。

这是一个 Spring 项目,第二部分中的代码位于一个名为“init”的 bean 的 init-method 中。前面提到的 DAO 也是在 Spring 中注册的。所以问题似乎是方法“init”正在挂起块 f.get() 的 bcoz 并且 Spring config 无法完成;它是一种循环依赖吗?我还没有找到最好的方法...

谢谢,

乔恩

【问题讨论】:

  • 什么是escacheLoader1 是什么?
  • @Sam:请查看新编辑的内容。谢谢。
  • 这一定是对cache.loadCache(); 的调用中的某些内容 - 尝试用虚拟打印语句替换该调用以查看它是否完成。如果您的打印语句有效,那么loadCache() 中的某些内容正在挂起。
  • 这似乎应该有效。如果在代码中调用cacheLoader1.call()而不是提交给Executor,是否有效?
  • 请看我的更新,谢谢!

标签: java concurrency future callable


【解决方案1】:

我找到了解决方案,很简单。

在初始化方法中,我创建了另一个线程,如下所示

ExecutorService es = Executors.newFixedThreadPool(2);
es.execute(cacheLoader);

并且 CacheLoader 实现了 Runnable(es1 是 ExecuteService 的另一个实例):

public class CacheLoader implements Runnable{
  public void run() {
    Future<Cache> f1 = es1.submit(new Callable<Cache>(){
        @Override
        public Cache call(){
            cache1.loadCache();
            return cache1;
        }
    });

    Future<Cache> f2 = es1.submit(new Callable<Cache>(){
        @Override
        public Cache call(){
            cache2.loadCache();
            return cache2;
        }
    });
    Cache c1 = f1.get();
    Cache c2 = f2.get();
  } //~end of run() ~
}

【讨论】:

    猜你喜欢
    • 2019-02-16
    • 1970-01-01
    • 1970-01-01
    • 2012-12-20
    • 1970-01-01
    • 2013-08-19
    • 2011-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多