Saturday 22 April 2017

Map

1. What is a Map?

Answer: Map does not directly implement java.utill.Collection interface unlike List and Set. It is part of Java Collection but doesn't carry the behavior like add(), remove() etc.
Map store the elements in key-value pair provided key should be unique. If you try to add two different values with same key, Map overwrites the old value with new value if key is same. So we can say that Map doesn't allow the duplicate keys
Example:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.HashMap;
import java.util.Map;

public class MapTest {

 public static void main(String[] args) {
  //1. Initializing Map
  Map<Integer, String> myMap = new HashMap<>();
  
  //2. Putting values in Map with corresponding keys
  myMap.put(1, "John");
  myMap.put(2, "Tom");
  myMap.put(3, "Jerry");
  myMap.put(4, "John"); //There won't be any overwriting as key is unique, Map allows duplicate values. 
  myMap.put(1, "Alan"); //It will overwrite the value against key "1" to "Alan" from "John"
  
  //3. Iterating over Map
  for(Integer key : myMap.keySet()){
   System.out.println("key: "+ key + ", value: "+myMap.get(key));
  }
  
 }

}
Important thing to note in above code are first at line number 15, Map will overwrite the value for key "1" from "John"(old value) to "Alan"(new value) as key is same.
and second at line number 14 Map won't overwrite as duplicate values are allowed inside Map provided keys are different.


2. Explain class hierarchy of Map?

AnswerClass hierarchy of Map is as follows: 
Fig : Map class hierarchy

Map has following implementation classes :
1. HashMap : It is default implementation of Map interface based on concept of hashing. It does not maintain the insertion order.
2. LinkedHashMap : It provides all the behavior of HashMap additionally it maintain the insertion order of keys.
3. TreeMap : It provides all the behavior of HashMap additionally it stores the keys in sorted order.
4. ConcurrentHashMap : It provides all the behavior of HashMap additionally it is designed for Multithreading environment. So we can say that it is concurrent version of HashMap.

3. How HashMap works?

AnswerIn order to explain how HashMap works you actually need to explain two behavior:
1. How we put values inside HashMap? 
Answer : put(key, value) method defined to put value into HashMap. 
2. How we get (retrieve) values from HashMap?
Answer : get(key) method defined to retrieve value from HashMap.


Before I will discuss how HashMap works first look at following three important methods which are use by HashMap internally : 
1. hashCode() : It is defined in Object class. hashCode() method returns a unique(except Hash-collision) number for every different object. For two different object it can return same hash code. It gives the hash code of current object.
2. equals(Object o) : It is also defined in Object class. It always returns true if two object are same otherwise false. For two different object it will never return true. It takes one object as input and compare it with current object. 
3. hash() : It is defined in HashMap class. Since hashCode() method returns long number hence in order to fit these big numbers in bucket (array of Entry object) size, HashMap takes help of hash() method. 

put(key, value) : put(key, value) method performs below steps internally :
1. It computes hash code of key by using hashCode() method declare in Object class.

2. It passes hascode returned in step 1 to internal hash(hash code) method. Output of hash() function gives the bucket location where value should store.
Bucket is nothing but array of entry object, You can assume it is like Entry<K,V> entry[];
So output of step 2 (hash() method) is nothing but just the index of entry array where new entry need to stored.

Fig : Entry array structure

Entry is a class which has two fields Key and Value. So HashMap first create object of Entry class with provided input key and input value and then stores this entry object in entry array(bucket). 

3. It uses bucket location returned in above step which is the location where value(Entry object) need to be stored. 

4. It checks whether or not some other Entry object is already stored in that location in order to check for duplicate key.

HashMap has created entry object with input key and value so far. Now it checks whether any other entry object already stored in that location.

5. if it found any Entry object at that location then It checks whether the key that already stored at the location is same as input key. If it finds both are same key then it simply replace the old Entry object with new Entry object otherwise it simply add new Entry object there with new key and value.
In order to verify both the keys are same or not HashMap checks for following scenario out of which only one holds true:
I. It first calls hashcode() method on both the keys(input key and already stored key). If hascode value of both the keys are same then HashMap call equals() method on both the keys and if equals() method returned true then it means both the keys are same(duplicate key). In this case HashMap replaces the old entry object with new entry object.
II. If hashCode() of both the keys are same but equals() method returned false then it means both are two different keys. In this case HashMap creates a LinkedList at given index and stored new entry object and old entry object both there. So in future if same scenario repeats for some different key then that will also get added to same linked list. 

In above figure we try to insert key = 6 and value = "NZ", now assume hash() method returned index location as 2 due to Hash- Collision. Since we already have one entry at index 2 with key = 3 hence Hashmap will take help of hashCode() and equals() method as mentioned above.
hashCode() method will return same hashCode (hashCode() method always returns same hashCode for same object every time)as it is case of Hash-Collision but equals() method will return false since key = 3 and key = 6 are two different object. HashMap will create a linked list here as shown and will store both the Entry object.
Note
-> Two different objects can produce same hash code, this scenario know as Hash-Collision. To handle this scenario HashMap does double check using equals() (since equals() method never returns true for two different object) method in order to ensure whether it's Hash-Collision(two different keys) or duplicate keys.
 -> Since input of hash() method of HashMap is hash code returned by hashCode() method. Hence if you pass same hash code the output(index location) will always be same. If the hash code of two different object are same then also hash() method will always return same index location for both the object.
-> There are rare scenarios where collision occurs in hash() method itself in this cases it returned the same index location for two different hash codes. To resolve this collision HashMap takes help of hashCode() and equals() method same as in case of HashCode-Collision. 
-> Please not from Java 8 Linked-list get converted into binary tree after it reaches to a defined size to improve performance.

get(key) : get(key) method performs below steps internally :
1. It computes hash code of key by using hashCode() method declare in Object class. As we discussed above hashCode() method always return same value for same object no matter how many time you invoke the method.

2. It passes hascode returned in step 1 to internal hash(hash code) method. Output of hash() function gives the bucket location from where we need to retrieve the value. It will return same bucket location as It returned in case of put() method for same key.

3. Next it will verify key using equals() method in order to handle Linked-list case. There are two possible scenario:
i. There will be only one entry object at given bucket location.
ii. There will be a Linked list at given bucket location.
First case is very straight forward where it will directly retrieve value form Entry object and will return the same. 
In second case it will iterate over all the nodes of Linked-list and will call equals() method on key stored at each node till equals method returns true. Node at which equals() method will return true, it will retrieve value from there and return the same.  

4. What is the contract between equals() and hashCode() method?

AnswerContract is as follows "Two object can produce two different hash code but they may or may not be equal(equals() method can return true of false) but if equals() method returns true for two object then they should produce same hash code".
Note: If you are using object of custom class(for example Employee) as key in HashMap then your class should fulfill above mentioned contract. 
If your custom class fails to fulfill above contract then HashMap won't work as it should. 
If you are using object of predefined classes like String, Integer etc as key in HashMap then contract is already in place.


5. What are the prerequisites to use object of custom class as key?

AnswerThere are no as such prerequisites to use any custom class' object as key. As I mentioned above that your class should follow contract of hashCode() and equals() method in order to use them as key. 
But as we know these two methods are defined in Object class and as per their default implementation in Object class they follow the contract.
So as far as your custom class doesn't override any of these two methods your custom class will get default behavior of these two methods. Hence you can use object of your custom class as key in Hashmap.
Note: If you want to overrides(modify) any of these two method in your custom class then you should override both the methods in order to maintain their contract.


6. What will be behavior of HashMap in below case if we use object of MyCustomKey as key?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class MyCustomKey{
 
 @Override
 public int hashCode() {
  return 1;
 }
 
 @Override
 public boolean equals(Object obj) {
  return super.equals(obj);
 }
 
}
AnswerIn above code we have overrided both hashCode() and equals() method. We kept the default implementation for equals() method and modified the hashCode() as such that it will always return 1 for all object.

If we use objects of MyCustomKey as key for HashMap then HashMap will behave as follows:
1. For all keys(objects of MyCustomKey) HashMap will get same hash code(which is 1) which will lead to same bucket location.
2. It will be a Hash-Collision scenario and to handle it HashMap will take help of  equals() method.
3. Since we have not modified equals() method and kept the default implementation hence equals will return false for two different keys(objects), hence HashMap will create Linked-List to store the input value. 
So all the keys(objects) will end up to same bucket location and HashMap will add all of them in same Linked-list one after one.
It will hurt the performance of HashMap since It has to go through entire linked list to add or get value every time.

Set

1. What is a Set?

Answer: Set is an unordered collection which does not maintain the insertion order unlike list.
Set doesn't allow the duplicate values unlike List. If you try to add same value again it will replace the old with new value.
Example: 

 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
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class SetExample {
 public static void main(String[] args) {
   // 1. Instantiated Set
   Set<Integer> mySet = new HashSet<Integer>();

   // 2. Adding elements to Set
   mySet.add(1);
   mySet.add(2);
   mySet.add(3);
   mySet.add(4);
   mySet.add(5);
   mySet.add(4);
   mySet.add(5);
   mySet.add(4);
   
   // 3. Iterating over Set
   Iterator<Integer> iterator = mySet.iterator();
   while (iterator.hasNext()) {
    System.out.println(iterator.next());
   }
 }
}
You can see above code is more like the code that we have for List as both implements java.utill.Collection interface. Methods  like add(), remove() etc. are declare in Collection interface only. 
In above code we are trying to add Integer value "4" 3 times and Integer value "5" 2 times. But in console you will get both these value printed only once as Set doesn't allow duplicate values.

2. What is underlying Data structure of Set?

AnswerSet doesn't implement any specific data structure directly instead it uses Map collection. 
Map is collection which based on the concept of Key-Value pair. So whenever you create an instance of Set, It internally creates and manages a instance of Map to store the values. Whenever you call add(value) method of Set, It internally make calls to Map's put(key, value) method and uses value need to be added in set as Key parameter and passes an empty instance of Object class as value parameter.
Example: Assume you want to add 3 in Set, then you will call() add method as below.
mySet.add(3);, Now Set's add() method will make call to Map's put() method as "map.put(3, new Object());".


3. Explain Set class Hierarchy?

AnswerClass hierarchy of Set is as follows:
Fig: Set class Hierarchy.

Set has following three implementations:
1. HashSet : It is considered as default implementation of Set. It uses HashMap internally. It doesn't maintain the insertion order as It is default implementation of Set.  
2. LinkedHashSet : It has all the behavior of Set except it maintains the insertion order as It uses LinkedHasMap internally.
3. TreeSet : It has all the behavior of Set except it store the values in sorted order. It uses as TreeMap internally.

4. Explain the situations when you will use List and Set?

Answer Which collection we should use, It all depends on your requirements. So in order to pick right collection you should have clear picture of your requirement. Let's discuss which collection fit where:
1. List :We should use List when your requirements required to maintain insertion order and you can or can not have duplicate values.
2. Set(HashSet) : Set Should be use when your requirement says that you can not have duplicate values and maintaining insertion order is not required.
3. LinkedHashSet : It should be use when your requirement says that you can not have duplicates values but you need to maintain insertion order.
4. TreeSet : It should be use when your requirement says that you can not have duplicates values but you need to maintain sorting order.


5. What will be the output of below program?


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

public class TreeSetExample {
 public static void main(String[] args) {
   Set<Object> mySet = new TreeSet<Object>(); //Hint : TreeSet maintains sorting order, 
           //TreeSet sorts the data after every insertion and deletion.
   mySet.add(new Integer(2));
   mySet.add(3);
   mySet.add("Hello");

   Iterator<Object> iterator = mySet.iterator();
   while (iterator.hasNext()) {
    System.out.println(iterator.next());
   }
 }
}
Answer Runtime Exception, It will throw ClassCastException at line number 11.
Since you have created mySet of type Object then It should allow String as well. Then why it throws Runtime exception?
It is because TreeSet uses Comparable to sort the values, Since you already have value of type Integer and you trying to insert value of type String. When you try to enter "Hello" at line number 11, Set will invoke the compareTo() method of  String class (which takes String as input) and will pass integer value to as parameter in order to decide sorting order. And here we will get ClassCastException saying that Integer can not be cast to String.

Sunday 16 April 2017

List

1. What is a List?

Answer: List is an ordered collection which maintains the insertion order.
Insertion order means "List always stores the elements in same order in which you have inserted. Hence Iteration over the list will give you the same order every time."
Example: 
 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
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListExample {

 public static void main(String[] args) {
  //1. Instantiated List
  List<Integer> myList = new ArrayList<Integer>(); 
  
  //2. Adding elements to List
  myList.add(1);
  myList.add(2);
  myList.add(3);
  myList.add(4);
  myList.add(5);
  
  //3. Iterating over List
  Iterator<Integer> iterator = myList.iterator();
  while(iterator.hasNext()){
   System.out.println(iterator.next());
  }
 }

}
No matters how many times you execute above code you will get same order as you have inserted.
Note: List allows duplicate elements. If you insert same element multiple times then list will treat each as an individual entry.

2. Explain List class hierarchy?

AnswerList is an interface which has following implementation classes:
1. ArrayList
2. LinkedList
3. CopyOnWriteArrayList
4. Vector.
Fig: List Class Hierarchy.
Note: ArrayList and LinkedList do not support concurrent operation i.e not suitable for multi threaded environment.
Vector and CopyOnWriteArrayList are designed for multi threaded environment.

3. What is difference between ArrayList and LinkedList?

AnswerArrayList and LinkedList both are the implementation of List interface. 
Both of them are the ordered collection and maintain the insertion order. So behavior wise both are same as both of them implement list interface.
The difference between these two is about their underlying data structure and their implementation
1. The underlying data structure for an ArrayList is an "Array", whereas the underlying data structure of a LinkedList is a "Linked List".
2. ArrayList allows random access(ArrayList is indexed based) of elements since it based on Array. whereas LiknedList doesn't allow random access as it is based on Linked List.
As we know Array data structure stores the values in continuous memory blocks. Hence in Array random access is possible. Below diagram shows memory allocation of an Array. Let's assume we want to access 36(element at 4th index), to retrieve 36 CPU will add 4 in base location(100) which will give 104 and that is location of 36. So point is in case of Array data structure there is no need of iterating over each element sequentially to retrieve desire value.
Fig: Array Data Structure
Fig: Linked List Data Structure

But Linked List data structure doesn't store the value in continuous memory block as shown above. Hence to access any value linked list need to follow links(pointer to next memory block).
3. Iterating over ArrayList or reading value from ArrayList is faster compare to LinkedList. As LinkedList doesn't support random access and in case of read operation it follows each and every links(pointer) whereas ArrayList directly jumps to desired value as we discussed above.
4. Insertion/Deletion operation is costlier(slower) in ArrayList compare to LinkedList. Insertion operation in LinkedList follow below steps:
1. Iterates over Linked List to reach desired location where we want to insert new element.
2. Adjust the pointers of two adjacent elements to accommodate new element.
Insertion operation in ArrayList follow below steps.
1. Reach to the desired location.
2. Shift every element to it's right from desired location in order to make room for new element.
3. Insert the element. 
It's clear that In case of Array, it's shifts every element(from index where we want to element) to their right which makes it slower for insertion operation.
So if there is 100 element in ArrayList and you want to insert at say 10th index, It will shift every element from and after 10th index to it's right in order to make space at 10th index.
Whereas LinkedList will just adjust pointers(links) of 10th and 11th index.
Deletion operation also has same behavior only difference is ArrayList shift every element to it's left to fill space of deleted element instead of right shift. LinkedList again adjust links to remove items from list.


4. When to use ArrayList over LinkedList or vice versa?

AnswerAs we discussed in last question "ArrayList performs better in case of read operation and LinkedList performs better in case of insertion/deletion".
So if your requirement is like that you are going to initialize List at once and there after you are only going to read those value (insertion/deletion operations are very less) through out your code, you should go for ArrayList.
But if your requirement is like that where you will frequently perform insertion/deletion on list through out your code, you should go for LinkedList.


5. Discuss time complexity of ArrayList and LinkedList?

Answer
Read operation: Time complexity of ArrayList is O(1) whereas for LinkedList it is O(n).
Insert/Delete operationTime complexity of ArrayList is O(n) whereas for LinkedList it is O(1).

Friday 14 April 2017

Callable and Future.

This article is in continuation of Executor Service. Please do read previous articles for detail about Executor Service. Callable is another way of writing task same as Runnable but it comes with additional benefits of returning results after completion of task.



1. What is Callable?

Answer: Callable<V> interface provides way of writing task same as Runnable but it has additional features of returning result after completion of task.
Callable interface has call() method which is same as run() method of Runnable interface. Only difference is that return type of run() method is void as it doesn't return anything but call() method has return type which is same as type of Callable.
Example: 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import java.util.concurrent.Callable;
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.newScheduledThreadPool(3); //We are creating a Thread pool of fixed size in this case 5.
  executorService.submit(myTaks);
 }
}


class Task implements Callable<Integer>{
 @Override
 public Integer call() {
  return 2;
 }
}
In above code we have Callable task of type Integer. As I said above return type of call() method would be same as type of Callable. In this code we have return type of call() as Integer same as type of task.
In above code we have returned 2 from call method. Now next question would come in mind how you will receive result that you have returned from call() method.
Since in this above code call() method is being executing by say thread-1 and we have started thread-1 from main() method. So the point is you are returning value from thread-1 and you need to receive it inside main thread. 
We can not directly return result form one thread to another thread, since both the thread has their own stack.

To solve above problem Java has concept of Future. Future class is use to receive value returned from call() method of Callable.


2. What is Future?

AnswerFuture class provides a way of receiving result which we return from call() method of Callable. If you check return type of Java's submit() method it is a Future object. submit() method immediately returns Future object. Then we can use Future object's get() method to get the result.
Note: get() method is a blocking method i.e it waits for result till call() method completes it's execution and returns value.
Example:

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

public class ExecutorServiceExample {
 public static void main(String[] args) throws InterruptedException, ExecutionException {
  Task myTaks = new Task();
  ExecutorService executorService = Executors.newScheduledThreadPool(3);
  Future future =  executorService.submit(myTaks);
  Integer result = (Integer) future.get();
  System.out.println("Result is ::"+result);
 }
}

class Task implements Callable<Integer>{
 @Override
 public Integer call() {
  return 2;
 }
}
In above code at line number 11 we have got Future object immediately. Then we have invoked get() method which will wait for call() method to complete and return result. Once call() method will return result we will get that in result variable.
In above code since we don't have any business logic inside call() method hence we got result immediately but in real scenario call() method takes some time to execute hence get() will remain block for that time period.
To simulate same let's consider below code:

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

public class ExecutorServiceExample {
 public static void main(String[] args) throws InterruptedException, ExecutionException {
  Task myTaks = new Task();
  ExecutorService executorService = Executors.newScheduledThreadPool(3);
  Future future =  executorService.submit(myTaks);
  Integer result = (Integer) future.get();
  System.out.println("Result is ::"+result);
 }
}

class Task implements Callable<Integer>{
 @Override
 public Integer call() throws InterruptedException {
  Thread.sleep(5000); // To simulate some task is being done
  return 2;
 }
}
Now in this case you will notice that get() method remains block for 5 seconds and result get printed after that.
Future is way of asynchronous communication as get() method wait for result while threads process in background.
Note: Future class has isDone() method which can be invoked to check whether a task is completed or still running. isDone() method returns true if task completed(call() method completed) otherwise false.


3. How exception works in case of Callable and Future? 

AnswerAs we know exception propagates inside stack only and each thread has their own stack. And in this case we have two different thread i.e. call() method is running inside say thread-1 and get() method is waiting inside main thread. So Java internally handles exception throws from call() method.
get() method of Future class throws 2 exception:
1. ExecutionException: If any exception occurs inside call() method then Java warps that exception inside ExecutionException and throws it to get() method and then get() method propagates ExcutionException to further.
2. InterrupteException: If current thread got interrupted(in above code it main thread) while waiting then Java throws InterrupteException.
Example: If you run below code you will get ExecutionException.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ExecutorServiceExample {
 public static void main(String[] args) throws InterruptedException, ExecutionException {
  Task myTaks = new Task();
  ExecutorService executorService = Executors.newScheduledThreadPool(3);
  Future future =  executorService.submit(myTaks);
  Integer result = (Integer) future.get();
  System.out.println("Result is ::"+result);
 }
}

class Task implements Callable<Integer>{
 @Override
 public Integer call() throws Exception {
  throw new Exception();
 }
}

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.