Tuesday, March 17, 2015

Decoupling tasks with an Executor Service

In implementations, you might need to run certain tasks in the background , in an asynchronous manner, so that your main tasks are not interrupted.  Java.util.concurrent.ExecutorService interface provides this asynchronous behavior and is very similar to a thread pool. 

Look at a scenario as below, where the usage of ExecutorService would be useful.
1. Customer makes payment for a specific order.
2. Payment is been accepted by the bank.
3. Send email notifications to the customer regarding payment acceptance.
4. Order is sent in for delivery. 

In a use case as above, you would need to proceed step 4 after step 2. But if we are to do all this in a single thread, step 4 would have to wait until step 3 is completed. Imagine a scenario where notifications are to be sent to a large number of customers. Therefore , we can use an executor service to proceed with step 3 task, that would decouple that step from the original flow, so that both can run in parallel. 

 Basic steps of an executor service
You can create an executor service in following ways depending on your use case. You can use one of the factory methods of Executor class.

 1. ExecutorService service1 = new Executors.newSingleThreadExecutor(); 

This will only create a single thread to proceed with the decoupled tasks.If the first task is not completed when the second task arrives, the second task will be queued up until the previous is completed.

2. ExecutorService service2 = new Executors.newFixedThreadPool(5);

Here you are creating 5 thread pools, and tasks delegated to this executor service can be executed using any one of these threads.

3. ExecutorService service3 =  new Executors.newScheduledThreadPool(5);

This executor service is similar to above, just that it can schedule the tasks delegated to it .

Once you create an executor service, there are few methods you could use to delegate tasks.
 1. executorService.execute (Runnable)
    This method takes a Runnable object and executes it asynchronously. For example ,
 
executorService.execute(new Runnable() {
    public void run() {
        System.out.println("Asynchronous task");
    }
});
 
2. executorService.submit(Runnable)
This method is similar to above, just that it returns a Future type object unlike execute method.   For example,
 executorService.submit(new Runnable() {

public void run() {
        System.out.println("Asynchronous task");
    }
   future.get();  
 });
 
future.get() would return null if the method inside run() is completed.
3. executorService.submit( Callable)
This method can be used if you need to return some result after the task execution. For example,
public Object call(){
 return "test" ;
}
future.get()
In this example .get() would print "test".

Next important step to remember, is to shutdown the executor service, once you have completed your task execution. So that the threads would not keep running .

executorService.shutDown() would stop executing any new tasks, and will shut down the service once all the current threads have completed executing tasks. But if you need an immediate shut down, you could use executorService.shutDownNow() method.

No comments:

Post a Comment