Friday 14 April 2017

Executor Service

This article is in continuation of Java Concurrent API. Please do read previous articles for other features of API. Executor Service comes handful if you writing multithreading code. These in built classes help programmers to handle lot of complex scenario with ease. It always recommended to use theses Executor Service instead of creating threads and mange them by your own.



1. What is ExecutorService?

Answer: Executor Services provide the features of creating and managing threads for you. Creating a new thread(when required) by your own at run-time is costly process in terms of timing, So to overcome this problem Java introduces concept of Executor Service. Executor Service in Java manages a kind of Thread Pool(a pool of threads which are ready to use), from where these thread can be used as required at run-time.

There are 2 things(in broader way) you need to do:
1. Create a task(Runnable or Callable) which will be use by threads to execute.
2. Create an Executor Service(where you can tell pool size as well) and submit your task to it.
Other than these you can terminate(shutdown) Executor Service.

There are two important class/interface that you should aware about in order to use Executor framework:
1. java.utill.concurrent.ExecutorService: This is an interface which is responsible for managing thread pool i.e submission of task, terminating Executor etc. This interface extends java.utill.concurrent.Executor interface.
2. java.utill.concurrent.Executors: This is a factory class responsible for creating a pool of thread of different types which I will cover later in this article. The methods of this factory class return instance of various thread pool executor classes available in Java. These all thread pool executor classes implements ExecuorService interface. 
Example: Let's see how you can use Executor Service.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorServiceExample {
 public static void main(String[] args) {
  Task myTaks = new Task();
  ExecutorService executorService = Executors.newFixedThreadPool(5); //We are creating a Thread pool of fixed size in this case 5.
  for(int i = 0 ; i < 5; i++){
   executorService.submit(myTaks);
  }
 }
}


class Task implements Runnable{
 @Override
 public void run() {
   System.out.println("Task is running by: "+ Thread.currentThread().getName());
 }
 
}
At line number 7 we have created a fixed size(5) Thread Pool(ThreadPoolExecutor) by using method(newFixedThreadPool) of Factory class Executors.
We have a runnable task whose object we have created at line number 6 named myTask.
From line number 8-10 we have submitted 5 task to Executor Service.
We are done form our side, No need to start the thread one by one etc. Everything will be mange by Executor Service.
What is happening behind the scene is since we have already created a thread pool of size 5, It means Executor Service has 5 threads which are ready to execute task. As soon as we have submitted task to Executor Service, It started picking task and assigned them to available threads.


Follow-up question 1: Could you please brief about Executor Service framework class hierarchy?

Answer: In below diagram I've covered important implementation classes only. But this will give you a good idea of overall hierarchy. 
Fig: Executor class hierarchy
Executor Interface is at top level of hierarchy which implements by ExecutorServices interface. Then we have abstract class AbstractExecutorService which extends by ThreadPoolExcecutor class. Other than this we have other thread pool executor classes too like SchedulerThreadPoolExecutor etc.
Executors is Factory class which is use to create different kind of thread pool.

Follow-up question 2Why Executor Services introduced by Java?

Answer: Creating thread in Java is very costly in terms of timing. Consider a scenario where you need threads at run time depends on request. If you are not using Executor Service then you need to create thread by your own at run time. Now assume If you need to create thousands of threads at run time then it will impact performance of application.
But If you are using Executor Service then you will get a thread pool of provided size where threads are created at start and ready to use. Assume we have created a thread pool of say size 100. It means first 100 request can directly serve by Executor Service without any delay as threads are ready to use. Once these threads complete their execution they come back to thread pool and can be used again to serve further request.

2. How to terminate(Shutdown) Executor Service?

Answer: Once you create Executor Service you can assign task to it as far as your application is running. Once your application terminates Executor Service get terminated automatically. Some time we need to shut down Executor Service explicitly in order to stopping it from taking any further task.
There are 2 methods available in ExecutorService interface for same:
1. shutDown().
2. shutDownNow().
Both these method use to shut down the Executor Service. Both of these do not accept any task after invocation of method. The only difference is "shutDown() method allows already submitted or running task to complete their execution before shutting down Executor Service, but shutDownNow() is kind of force shut down where it immediately shut down the Executor Service without giving chance to submitted or running task to complete their execution."
Note: shutDownNow() method in order to shut down immediately
interrupts the running task hence you will receive interrupted exception after invocation of shutDownNow() if any task is running.

 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
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorServiceExample {
 public static void main(String[] args) {
  Task myTaks = new Task();
  ExecutorService executorService = Executors.newFixedThreadPool(5); //We are creating a Thread pool of fixed size in this case 5.
  for(int i = 0 ; i < 5; i++){
   executorService.submit(myTaks);
  }
  executorService.shutdown(); //executorService.shutdownNow()
  executorService.submit(myTaks);
 }
}


class Task implements Runnable{
 @Override
 public void run() {
   try {
    Thread.sleep(1000); // Just to simulate some long work is being done
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("Task is running by: "+ Thread.currentThread().getName());
 }
 
}

In above code we are calling shutDown() at line 10, hence all task we submitted prior to this will execute fine and Executor Service will wait for these task to finish before shutting down.
But the task that we are trying to submit at line number 12 will get rejected since shutDown() already invoked and if you run above code you will get rejection exception for same. So Executor Service will not take nay new task but will wait for already submitted tasks.
Now If you comment out shutDown() and call shutDownNow() instead. It will immediately shut down the Executor Service without waiting for running task. If you run above code with shutDownNow() you will get Interrupted exception at console.

3. What is difference between FixedThreadPool, CachedThreadPool and ScheduleThreadPool?

Answer: All these three are thread pool only. Difference between these 3 is that how they manages threads.
1. FixedThreadPool : It is thread pool of fixed size where size need to provide while creating. It means it can process a fixed number(equal to size of pool) of task at a time. If additional tasks submitted when all other threads are busy then they will need to wait in queue till any of thread become free. 
For example you have created a thread pool of size 5. Now you have submitted 10 tasks to Executor Service then first 5 task will pick up by the threads and other 5 will need to wait for threads to become free.
2. CachedThreadPool :  It is a thread pool where we do not need to provide size of pool. It creates new thread as required and also use already created thread if they are available. In this case tasks do not need to wait for threads to become available unlike FixedThreadPool, Since it creates new thread as required. 
Note: CachedThreadPool removes the threads from pool if they are sitting idle for 60 seconds in order to avoid unnecessary threads in pool.
For example you have created a thread pool of size 5. Now you have submitted 10 tasks to Executor Service then all 10 task will pick up by the threads as CachedThreadPool creates thread if all threads in pool are busy
3. ScheduleThreadPool : As name suggests we use it to schedule tasks/commands to run after a given delay or to run periodically.

4. What is difference between execute() and submit() method?

Answer: Both methods are use to submit tasks to Executor Service. submit() method provide all the feature of execute() with some additional supports.
1. execute() method can only accept tasks which are Runnable type. But submit() method accept both kind of tasks i.e. Runnable and Callable.
2. As we came to know execute() method only accept Runnable tasks, hence it doesn't return anything but since submit() method supports Callable tasks too hence it returns Future object after execution.

No comments:

Post a Comment