ExecutorService类型中的方法invokeAll不适用于参数错误

时间:2013-09-05 19:56:59

标签: java multithreading executorservice

我正在开展一个项目,我将在其中使用不同的Bundles。我们举一个例子,假设我有5个Bundle,每个bundle都有一个方法名process

以下是我应该做的事情 -

  1. 我需要使用多线程代码并行调用所有这5个Bundles process方法,然后写入数据库。我不确定这样做的正确方法是什么?我应该有五个帖吗?每个捆绑一个线程?但是在那种情况下会发生什么,假设我有50个捆绑,那么我将有50个线程?
  2. 而且,我也希望有超时功能。如果任何捆绑包占用的时间超过了我们设置的阈值,那么它应该超时并记录为该捆绑包花费了大量时间的错误。
  3. 我所做的以下尝试很可能是有缺陷的,并且错误处理绝不是完整的。但不知何故,我总是在这一行得到错误 -

    pool.invokeAll

    错误是 -

    The method invokeAll(Collection<? extends Callable<T>>, long, TimeUnit) in the type ExecutorService is not applicable for the arguments (List<ModelFramework.ProcessBundleHolderEntry>, int, TimeUnit)
    

    下面是我的方法,它将以多线程方式调用所有包中的process method

    public void processEvents(final Map<String, Object> eventData) {
        ExecutorService pool = Executors.newFixedThreadPool(5);
        List<ProcessBundleHolderEntry> entries = new ArrayList<ProcessBundleHolderEntry>();
    
        Map<String, String> outputs = (Map<String, String>)eventData.get(BConstants.EVENT_HOLDER);
    
        for (BundleRegistration.BundlesHolderEntry entry : BundleRegistration.getInstance()) {
            ProcessBundleHolderEntry processBundleHolderEntry = new ProcessBundleHolderEntry(entry, outputs);
            entries.add(processBundleHolderEntry);
        }
    
        try {
    
            // somehow I always get an error at invokeAll method. Is there anything wrong?
            List<Future<Object>> futures = pool.invokeAll(entries, 30, TimeUnit.SECONDS);
            for (int i = 0; i < futures.size(); i++) {
                // This works since the list of future objects are in the
                // same sequential order as the list of entries
                Future<Object> future = futures.get(i);
                ProcessBundleHolderEntry entry = entries.get(i);
                if (!future.isDone()) {
                    // log error for this entry
                }
            }
        } catch (InterruptedException e) {
            // handle this exception!
        }
    }
    

    其次,我已经在ModelFramework类中添加了线程的Callable实现

    public class ProcessBundleHolderEntry implements Callable {
        private BundleRegistration.BundlesHolderEntry entry;
        private Map<String, String> outputs;
    
        public ProcessBundleHolderEntry(BundleRegistration.BundlesHolderEntry entry, Map<String, String> outputs) {
            this.entry = entry;
            this.outputs = outputs;
        }
    
        public Object call() throws Exception {
            final Map<String, String> response = entry.getPlugin().process(outputs);
            // write to the database.
            System.out.println(response);
            return response;
        }
    }
    

    任何人都可以帮助我解决我得到的错误吗?还有人可以告诉我上述方法是否有任何问题,或者是否有更好,更有效的方法做同样的事情?

    任何帮助都将受到赞赏。

2 个答案:

答案 0 :(得分:1)

没关系,我发现了实际的问题

public class ProcessBundleHolderEntry implements Callable {

应定义为

public class ProcessBundleHolderEntry implements Callable<Object> {

以匹配以下声明中的Object类型

List<Future<Object>> futures = pool.invokeAll(entries, 30, TimeUnit.SECONDS);

invokeAll方法的签名是

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                              long timeout, TimeUnit unit)

答案 1 :(得分:1)

  

我所做的以下尝试很可能是有缺陷的,并且错误处理绝不是完整的。但不知何故,我总是在这一行得到错误 -

如果您希望ProcessBundleHolderEntry返回Callable<Object>,我认为问题是invokeAll(...)应该实施List<Future<Object>>。我刚刚编译了你的代码,这解决了这个问题。

在我看来它应该实现Callable<Map<String, String>>。然后call方法应该返回正确的类型:

public Map<String, String> call() throws Exception {

然后invokeAll(...)方法会返回正确的List<Future<Map<String, String>>

另一个(尽管有点奇怪)想法是将this退出call()方法。拥有ProcessBundleHolderEntry implements Callable<ProcessBundleHolderEntry>并在从this返回call()之前在条目中记录回复。然后,您无需对条目进行get(i)以匹配它。然后在一个对象中有条目,输出和响应。