【问题标题】:invokeAll vs CompletionServiceinvokeAll 与 CompletionService
【发布时间】:2013-05-17 03:41:01
【问题描述】:

我有一个由多个线程访问的类,每个线程请求这个类的一个方法。每个方法依次执行多个 Callables。该类使用 ExecutorService 中的 threadPool 通过 invokeAll((Collection>) executableTasks) 方法执行这些 Callables。 设置如下所示:

public MyClass {
private final ExecutorService threadPool = Runtime.getRuntime().availableProcessors();

public void method1() {
 List<SomeObject> results = new ArrayList<>();
 List<Callable<Void>> tasks = new ArrayList<Callable<Void>>();
 tasks.add(new Callable<Void>(){ ... results.add(someObject);} );
 threadPool.invokeAll(tasks);
}

public void method2() {
 List<SomeObject> results = new ArrayList<>();
 List<Callable<Void>> tasks = new ArrayList<Callable<Void>>();
 tasks.add(new Callable<Void>(){ ... results.add(someObject);} );
 threadPool.invokeAll(tasks);
}

}

我很困惑这是否会同时执行类中的任务,或者 invokeAll() 会阻塞执行直到一个方法中的任务完成(意味着执行将在方法内部同时发生,但不在类级别)?或者我应该使用 CompletionService 来找出任务的相应结果吗?

【问题讨论】:

    标签: java concurrency


    【解决方案1】:

    ExecutorService#invokeAll 并发执行所有任务,但调用本身会阻塞,直到所有任务完成。

    例如,假设您有三个任务需要 6 秒、2 秒和 10 秒才能完成。如果您要同步执行这些操作,则至少需要 6 + 2 + 10 = 18 秒。但是,使用 invokeAll(在足够大的线程池上),这可能只需要最长的时间,即 10 秒。

    这意味着method1()method2() 方法都是阻塞方法,因为使用了invokeAll()。当您调用method1() 时,它将阻塞,直到添加到可调用列表中的所有请求都完成为止。 method2() 也是如此。如果这些方法是从不同的线程调用的,那么这两个方法中的任务将同时执行。

    如果您希望方法是异步的,您需要为方法中的每个任务单独调用 threadPool.submit(callable) 并将返回的期货收集到一个列表中。您可以返回一个 List 或使用 CompletionService 来帮助解决这个问题,是的。

    PS - 您的示例中的这一行将不起作用:

    ExecutorService threadPool = Runtime.getRuntime().availableProcessors();
    

    我想你想要这个:

    ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    

    希望这会有所帮助。

    【讨论】:

    • “所以,是的,执行将在特定方法中同时发生,但不在类级别”:但这两个方法在 2 个不同的线程中被调用,那么为什么这些任务(来自方法 1 和方法 2 ) 不会同时执行
    • 哎呀,我想应该读过第一句话。我已经确定了我的答案。感谢您的提示!
    • @Cody 同意这两个建议:方法被阻塞和线程池定义中的错字。
    【解决方案2】:

    对我来说,这将在课堂上同时执行任务。 invokeAll() 一直等到它的所有任务都完成了,但这是针对当前线程的,当这个线程在等待时,其他线程可以同时执行它的任务

    【讨论】:

    • 是的,执行也支持这个。我对有人评论“invokeAll 等待所有任务完成”感到困惑。
    【解决方案3】:

    根据 Java 规范invokeAll,可以同时独立地执行所有任务。并且重复调用invokeAll会做同样的事情,即调用invokeAll不会阻塞任务的执行。

    访问:http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/AbstractExecutorService.html

    【讨论】:

    • 它说:执行给定的任务,返回一个持有其状态和结果的期货列表当所有完成时
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多