Table of Contents
In this post, we will see about Java ExecutorCompletionService example.
ExecutorCompletionService
class implements CompletionService
. This class returns Future object in completion order.
Why you may need to use ExecutorCompletionService:
Let’s understand with the help of scenario:
Let’s say you have 5 tasks, you submit it to the executors and you want to perform some operation as soon as task completes.Let’s also assume that the first task takes the longest time.
If you use Executors in this case, when you call future.get() on the first task, get operation will be blocked and even though other tasks may have completed, you won’t be able to proceed further.
To solve this issue, you can use ExecutorCompletionService
. ExecutorCompletionService
returns futures objects based on completion order, so whichever task executes first, will be returned first. You just need to call executorCompletionService.take()
to get completed Future object.
Java ExecutorCompletionService example:
Let’s create a very simple example.
Step 1: Create a Callable task named "MultiplyingTask.java".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package org.arpit.java2blog; import java.util.concurrent.Callable; public class MultiplyingTask implements Callable{ int a; int b; long sleepTime; String taskName; public MultiplyingTask(String taskName,int a, int b, long sleepTime) { this.taskName=taskName; this.a=a; this.b=b; this.sleepTime=sleepTime; } @Override public Integer call() throws Exception { System.out.println("Started taskName: "+taskName); int result=a*b; Thread.sleep(sleepTime); System.out.println("Completed taskName: "+taskName); return result; } } |
Step 2: Create a class named "FutureTaskMain". This will be our main class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
package org.arpit.java2blog; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ExecutionCompletionServiceaMain { public static void main(String[] args) { MultiplyingTask multiplyingTask1= new MultiplyingTask("Task 1",10,20,2000l); MultiplyingTask multiplyingTask2= new MultiplyingTask("Task 2",30,40,4000l); MultiplyingTask multiplyingTask3= new MultiplyingTask("Task 3",40,50,3000l); MultiplyingTask multiplyingTask4= new MultiplyingTask("Task 4",50,60,1000l); ExecutorService executorService = Executors.newFixedThreadPool(4); CompletionService<Integer> executorCompletionService= new ExecutorCompletionService<>(executorService); List<Future<Integer>> futures = new ArrayList<Future<Integer>>(); futures.add(executorCompletionService.submit(multiplyingTask1)); futures.add(executorCompletionService.submit(multiplyingTask2)); futures.add(executorCompletionService.submit(multiplyingTask3)); futures.add(executorCompletionService.submit(multiplyingTask4)); for (int i=0; i<futures.size(); i++) { try { Integer result = executorCompletionService.take().get(); System.out.println("Result: " +result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } executorService.shutdown(); } } |
Let’s run above program to check the output:
Started taskName: Task 3
Started taskName: Task 2
Started taskName: Task 4
Completed taskName: Task 4
Result: 3000
Completed taskName: Task 1
Result: 200
Completed taskName: Task 3
Result: 2000
Completed taskName: Task 2
Result: 1200
As you can see with the output, All four tasks started simuntaneously but We retrieved the results based on the completion order with the help of executorCompletionService.take().get()
rather than calling get()
method on future object.
That’s all about Java ExecutorCompletionService example.