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

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找出任务的相应结果?

最佳答案

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());


希望这可以帮助。

07-26 02:04