我刚在this blog post找到了CompletionService。然而,这并没有真正展示出CompletionService相对于标准ExecutorService的优势。同样的代码也可以用这两种方法来编写。那么,什么时候CompletionService是有用的呢?
你能给出一个简短的代码样本,让它清晰明了吗?例如,此代码示例仅显示了不需要CompletionService的位置(=等同于ExecutorService)
ExecutorService taskExecutor = Executors.newCachedThreadPool();
// CompletionService<Long> taskCompletionService =
// new ExecutorCompletionService<Long>(taskExecutor);
Callable<Long> callable = new Callable<Long>() {
@Override
public Long call() throws Exception {
return 1L;
}
};
Future<Long> future = // taskCompletionService.submit(callable);
taskExecutor.submit(callable);
while (!future.isDone()) {
// Do some work...
System.out.println("Working on something...");
}
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
发布于 2011-04-07 19:05:12
使用ExecutorService
,一旦提交了要运行的任务,就需要手动编写代码来高效地获取任务完成的结果。
使用CompletionService
,这几乎是自动化的。在您所呈现的代码中,差异并不是很明显,因为您只提交了一个任务。但是,假设您有一个要提交的任务列表。在下面的示例中,向CompletionService提交了多个任务。然后,它不会尝试找出哪个任务已经完成(以获取结果),而只是要求CompletionService实例在结果可用时返回这些结果。
public class CompletionServiceTest {
class CalcResult {
long result ;
CalcResult(long l) {
result = l;
}
}
class CallableTask implements Callable<CalcResult> {
String taskName ;
long input1 ;
int input2 ;
CallableTask(String name , long v1 , int v2 ) {
taskName = name;
input1 = v1;
input2 = v2 ;
}
public CalcResult call() throws Exception {
System.out.println(" Task " + taskName + " Started -----");
for(int i=0;i<input2 ;i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
System.out.println(" Task " + taskName + " Interrupted !! ");
e.printStackTrace();
}
input1 += i;
}
System.out.println(" Task " + taskName + " Completed @@@@@@");
return new CalcResult(input1) ;
}
}
public void test(){
ExecutorService taskExecutor = Executors.newFixedThreadPool(3);
CompletionService<CalcResult> taskCompletionService = new ExecutorCompletionService<CalcResult>(taskExecutor);
int submittedTasks = 5;
for (int i=0;i< submittedTasks;i++) {
taskCompletionService.submit(new CallableTask (
String.valueOf(i),
(i * 10),
((i * 10) + 10 )
));
System.out.println("Task " + String.valueOf(i) + "subitted");
}
for (int tasksHandled=0;tasksHandled<submittedTasks;tasksHandled++) {
try {
System.out.println("trying to take from Completion service");
Future<CalcResult> result = taskCompletionService.take();
System.out.println("result for a task availble in queue.Trying to get()");
// above call blocks till atleast one task is completed and results availble for it
// but we dont have to worry which one
// process the result here by doing result.get()
CalcResult l = result.get();
System.out.println("Task " + String.valueOf(tasksHandled) + "Completed - results obtained : " + String.valueOf(l.result));
} catch (InterruptedException e) {
// Something went wrong with a task submitted
System.out.println("Error Interrupted exception");
e.printStackTrace();
} catch (ExecutionException e) {
// Something went wrong with the result
e.printStackTrace();
System.out.println("Error get() threw exception");
}
}
}
}
发布于 2011-02-07 06:19:59
基本上,如果您希望并行执行多个任务,然后按它们的完成顺序使用它们,则可以使用CompletionService
。所以,如果我执行5个作业,CompletionService
会给我第一个完成的作业。在只有一个任务的示例中,除了提交Callable
的能力之外,并没有提供比Executor
更多的值。
发布于 2012-02-04 01:46:22
首先,如果我们不想浪费处理器时间,我们就不会使用
while (!future.isDone()) {
// Do some work...
}
我们必须使用
service.shutdown();
service.awaitTermination(14, TimeUnit.DAYS);
这段代码的不好之处在于它会关闭ExecutorService
。如果我们想继续使用它(即我们有一些递归任务创建),我们有两个选择: invokeAll或ExecutorService
。
invokeAll
将一直等到所有任务完成。ExecutorService
为我们提供了逐个获取或投票结果的能力。
最后是递归示例:
ExecutorService executorService = Executors.newFixedThreadPool(THREAD_NUMBER);
ExecutorCompletionService<String> completionService = new ExecutorCompletionService<String>(executorService);
while (Tasks.size() > 0) {
for (final Task task : Tasks) {
completionService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return DoTask(task);
}
});
}
try {
int taskNum = Tasks.size();
Tasks.clear();
for (int i = 0; i < taskNum; ++i) {
Result result = completionService.take().get();
if (result != null)
Tasks.add(result.toTask());
}
} catch (InterruptedException e) {
// error :(
} catch (ExecutionException e) {
// error :(
}
}
https://stackoverflow.com/questions/4912228
复制相似问题