Difference between ExecutorService and CompletionService with java example
ExecutorService
and CompletionService
are both interfaces in the Java concurrency framework that provide a way to execute tasks asynchronously in a multithreaded environment. However, they serve different purposes.
ExecutorService
provides a way to submit tasks for execution and manage the lifecycle of the threads that execute the tasks. It allows you to submit tasks and receive a Future
object, which you can use to check the status of the task, get its result, or cancel it.
CompletionService
, on the other hand, is a higher-level abstraction that allows you to retrieve the results of tasks as soon as they complete, regardless of the order in which they were submitted. It uses a BlockingQueue
to hold the results of completed tasks and provides a way to retrieve the results in the order in which they complete.
Here is an example that demonstrates the difference between ExecutorService
and CompletionService
. Suppose we have a list of tasks that take a variable amount of time to execute, and we want to execute them asynchronously and print out their results as soon as they complete:
ExecutorService executor = Executors.newFixedThreadPool(5); List<Callable<String>> tasks = Arrays.asList( () -> { Thread.sleep(1000); return "Task 1"; }, () -> { Thread.sleep(500); return "Task 2"; }, () -> { Thread.sleep(2000); return "Task 3"; }, () -> { Thread.sleep(1500); return "Task 4"; }, () -> { Thread.sleep(3000); return "Task 5"; } ); // Using ExecutorService List<Future<String>> futures = executor.invokeAll(tasks); for (Future<String> future : futures) { String result = future.get(); System.out.println(result); } executor.shutdown(); // Using CompletionService CompletionService<String> completionService = new ExecutorCompletionService<>(executor); for (Callable<String> task : tasks) { completionService.submit(task); } for (int i = 0; i < tasks.size(); i++) { String result = completionService.take().get(); System.out.println(result); } executor.shutdown();
In this example, we create a fixed thread pool with 5 threads and submit a list of tasks to the pool. We then use invokeAll
method to submit all the tasks to the ExecutorService and get back a list of Future
objects that we can use to retrieve the results of the tasks.
Alternatively, we can use the CompletionService
interface to submit the tasks and retrieve the results as soon as they complete, without waiting for the others to finish. In the loop that retrieves the results, we use the take
method to retrieve the next completed task from the BlockingQueue
, which will block if there are no completed tasks yet. We then call get
on the Future
object to retrieve the result of the task.
In summary, ExecutorService
is a more general-purpose interface for managing the execution of tasks in a thread pool, while CompletionService
is a higher-level abstraction that allows you to retrieve the results of tasks as soon as they complete.