Thursday 4 September 2014

Executor and ExecutorService in Java

Executor Framework (java.util.concurrent.Executors) included in jdk1.5. Before explaining what, why and how? I will explain little background about Thread. As you know Thread in java is used for parallel execution in new VM stack and it created by two ways Thread class and Runnable interface. To know more about thread click here
When you use Executor Framework then no need to create Thread explicitly. And multiple thread can execute  tasks concurrently. These multiple Thread maintained inside pool called Thread pool. Once Thread will be allocated to process one task it can't allocated to process other task until Thread is free. Whenever any Thread finish it execution it notify to executor framework to take up another task. Hence we can say that Executor Framework implicitly maintain the Thread allocation for the task.
We can have n number of Treads in the Thread pool. Thread can be reused by multiple time. So, Executor is very useful from performance point of view. because it will save the time to create the Thread again and again, as you know creating Thread inside is very heavy process.
An Executor is normally used instead of explicitly creating threads. For example, rather than invoking new Thread(new(RunnableTask())).start() for each of a set of tasks, you might use:
 Executor executor = anExecutor;
 executor.execute(new RunnableTask1());
 executor.execute(new RunnableTask2());
 
So, java.util.concurrent.ExecutorService provide us the way to execute the task by Thread which present in the pool. And Executors factory class provide the factory method to create the Thread pool.
e.g-

ExecutorService executorService = Executors.newFixedThreadPool(10);

executorService.execute(new Runnable() {
    public void run() {
        System.out.println("Runnable task");
    }
});

executorService.shutdown();
 
ExecutorService is created here using the newFixedThreadPool() factory method. This creates a thread pool with 10 threads executing tasks.
Later on, an anonymous implementation of the Runnable interface is passed to the execute() method. This causes the Runnable to be executed by one of the threads in the ExecutorService.
And last line we are shutting the executorService.When you are done using the ExecutorService you should shut it down, so the threads do not keep running.

Apart from newFixedThreadPool() factory method some other method are also present in Executors factory class to create the ExecutorService e.g.-
newFixedThreadPool(),
newScheduledThreadPool().
As you have seen in above example that Runnable task is executed by execute() method of executorService. But apart from this we have some other ways to submit/execute the task, which is listed below-
execute(Runnable)- Only Runnable task can be execute by this and it doesn't return any value. as you have seen in above example.

submit(Runnable/Callable)- Runnable and Callable task both can be execute by submit method. and it always return Future.e.g.-
 
Future future = executorService.submit(new Runnable() {
    public void run() {
        System.out.println("Runnable task");
    }
});

future.get(); 

or

Future future = executorService.submit(new Callable(){
    public Object call() throws Exception {
        System.out.println("Callable task");
        return "Callable Result";
    }
});

System.out.println("future.get() = " + future.get());



invokeAny(collection)-
The invokeAny() method takes a collection of Callable objects, or subinterfaces of Callable. Invoking this method does not return a Future, but returns the result of one of the Callable objects. You have no guarantee about which of the Callable's results you get. Just one of the ones that finish.
If one of the tasks complete (or throws an exception), the rest of the Callable's are cancelled.

ExecutorService executorService = Executors.newSingleThreadExecutor();

Set<Callable<String>> callables = new HashSet<Callable<String>>();
 
callables.add(new Callable<String>() {
    public String call() throws Exception {
        return "First task ";
    }
});  
...................
......................
String result = executorService.invokeAny(callables);

System.out.println("result = " + result);

executorService.shutdown(); 
 
invokeAll(collection)-
The invokeAll() method invokes all of the Callable objects you pass to it in the collection passed as parameter. The invokeAll() returns a list of Future objects via which you can obtain the results of the executions of each Callable.
Keep in mind that a task might finish due to an exception, so it may not have "succeeded". There is no way on a Future to tell the difference.

ExecutorService executorService = Executors.newSingleThreadExecutor();

Set<Callable<String>> callables = new HashSet<Callable<String>>();

callables.add(new Callable<String>() {
    public String call() throws Exception {
        return "First task ";
    }
}); 
 
..................................
.................................
 
List<Future<String>> futures = executorService.invokeAll(callables);

for(Future<String> future : futures){
    System.out.println("future.get = " + future.get());
}

executorService.shutdown();

 

No comments:

Post a Comment