Friday, February 24, 2017

Advance Collection Framework Concepts

HashSet


HashSet uses HashMap internally to store it’s objects. Whenever you create a HashSet object, one HashMap object associated with it is also created. This HashMap object is used to store the elements you enter in the HashSet. The elements you add into HashSet are stored as keys of this HashMap object. The value associated with those keys will be a constant.





HashMap


HashMap works on the principle of hashing, we have put() and get() method for storing and retrieving object from HashMap.When we pass both key and value to put() method to store on HashMap, it uses key object hashcode() method to calculate hashcode and them by applying hashing on that hashcode it identifies bucket location for storing value object. While retrieving it uses key object equals method to find out correct key value pair and return value object associated with that key. HashMap uses linked list in case of collision and object will be stored in next node of linked list.
Important point to mention is that HashMap in Java stores both key and value object as Map.Entry in a bucket which is essential to understand the retrieving logic.

What will happen if two different objects have the same hashcode?
Now from here onwards real confusion starts, sometime candidate will say that since hashcode is equal, both objects are equal and HashMap will throw exception or not store them again etc, Then you might want to remind them about equals() and hashCode() contract that two unequal objects in Java can have same hashcode. Some will give up at this point and few will move ahead and say "Since hashcode is same, bucket location would be same and collision will occur in HashMap Since HashMap uses LinkedList to store object, this entry (object of Map.Entry comprise key and value ) will be stored in LinkedList

HashMap Changes in JDK 1.7 and JDK 1.8

There is some performance improvement done on HashMap and ArrayList from JDK 1.7, which reduce memory consumption. Due to this empty Map are lazily initialized and will cost you less memory. Earlier, when you create HashMap e.g. new HashMap() it automatically creates an array of default length e.g. 16. After some research, Java team found that most of this Map are temporary and never use that many elements, and only end up wasting memory. Also, From JDK 1.8 onwards HashMap has introduced an improved strategy to deal with high collision rate. Since a poor hash function e.g. which always return location of same bucket, can turn a HashMap into linked list, i.e. converting get() method to perform in O(n) instead of O(1) and someone can take advantage of this fact, Java now internally replace linked list to a binary true once certain threshold is breached. This ensures performance or order O(log(n)) even in the worst case where a hash function is not distributing keys properly.


Some other Concepts
  • The concept of hashing
  • Collision resolution in HashMap
  • Use of equals () and hashCode () and their importance in HashMap?
  • The benefit of the immutable object?
  • Race condition on HashMap  in Java
  • Resizing of Java HashMap
  • Immutable key object
  • Load factor and balancing

ConcurrentHashMap

ConcurrentHashMap performs better than earlier two because it only locks a portion of Map, instead of whole Map, which is the case with Hashtable and synchronized Map. CHM allows concurred read operations and the same time maintains integrity by synchronizing write operations.

ConcurrentHashMap is introduced as an alternative of Hashtable and provided all functions supported by Hashtable with an additional feature called "concurrency level", which allows ConcurrentHashMap to partition Map. ConcurrentHashMap allows multiple readers to read concurrently without any blocking. This is achieved by partitioning Map into different parts based on concurrency level and locking only a portion of Map during updates. Default concurrency level is 16, and accordingly Map is divided into 16 part and each part is governed with a different lock. This means, 16 thread can operate on Map simultaneously until they are operating on different part of Map. This makes ConcurrentHashMap high performance despite keeping thread-safety intact. Though, it comes with a caveat. Since update operations like put(), remove(), putAll() or clear() is not synchronized, concurrent retrieval may not reflect most recent change on Map.

 Concurrency-Level: Defines the number which is an estimated number of concurrently updating threads. The implementation performs internal sizing to try to accommodate this many threads.

Load-Factor: It's a threshold, used to control resizing.

Initial Capacity: The implementation performs internal sizing to accommodate these many elements.


When to use ConcurrentHashMap in Java

ConcurrentHashMap is best suited when you have multiple readers and few writers. If writers outnumber reader, or writer is equal to reader, than performance of ConcurrentHashMap effectively reduces to synchronized map orHashtable. Performance of CHM drops, because you got to lock all portion of Map, and effectively each reader will wait for another writer, operating on that portion of Map. ConcurrentHashMap is a good choice for caches, which can be initialized during application start up and later accessed my many request processing threads. As javadoc states, CHM is alsoa good replacement of Hashtable and should be used whenever possible, keeping in mind, that CHM provides slightly weeker form of synchronization than Hashtable.




Example to understand differnce between ConcurrentHashMap and HashMap

package com.journaldev.util;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {

 public static void main(String[] args) {

  //ConcurrentHashMap
  Map<String,String> myMap = new ConcurrentHashMap<String,String>();
  myMap.put("1", "1");
  myMap.put("2", "1");
  myMap.put("3", "1");
  myMap.put("4", "1");
  myMap.put("5", "1");
  myMap.put("6", "1");
  System.out.println("ConcurrentHashMap before iterator: "+myMap);
  Iterator<String> it = myMap.keySet().iterator();

  while(it.hasNext()){
   String key = it.next();
   if(key.equals("3")) myMap.put(key+"new", "new3");
  }
  System.out.println("ConcurrentHashMap after iterator: "+myMap);

  //HashMap
  myMap = new HashMap<String,String>();
  myMap.put("1", "1");
  myMap.put("2", "1");
  myMap.put("3", "1");
  myMap.put("4", "1");
  myMap.put("5", "1");
  myMap.put("6", "1");
  System.out.println("HashMap before iterator: "+myMap);
  Iterator<String> it1 = myMap.keySet().iterator();

  while(it1.hasNext()){
   String key = it1.next();
   if(key.equals("3")) myMap.put(key+"new", "new3");
  }
  System.out.println("HashMap after iterator: "+myMap);
 }

}
When we try to run the above class, output is
ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1}
ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1}
HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1}
Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
 at java.util.HashMap$KeyIterator.next(HashMap.java:828)
 at com.test.ConcurrentHashMapExample.main(ConcurrentHashMapExample.java:44)

Core Java - Part 2


Java Multithreading

There are two types of threads in an application – user thread and daemon thread. When we start an application, main is the first user thread created and we can create multiple user threads as well as daemon threads. When all the user threads are executed, JVM terminates the program.We can create Threads by either implementing Runnable interface or by extending Thread Class.
Thread t = new Thread(new Runnable(){
    @Override
    public void run() {
    }
});
Thread Life cycle


Point to remember -:
  • Syntax of Thread class:  public class Thread extends Object implements Runnable
  • Method of Runnable interface: void run() 


Java Thread Sleep

Thread.sleep() method can be used to pause the execution of current thread for specified time in milliseconds. The argument value for milliseconds can’t be negative, else it throws IllegalArgumentException.
1
Thread.sleep();

Java Thread Sleep important points:

  1. It always pause the current thread execution.
  2. The actual time thread sleeps before waking up and start execution depends on system timers and schedulers. For a quiet system, the actual time for sleep is near to the specified sleep time but for a busy system it will be little bit more.
  3. Thread sleep doesn’t lose any monitors or locks current thread has acquired.
  4. Any other thread can interrupt the current thread in sleep, in that case InterruptedException is thrown.
  5. Sleep is a static method of Thread class.

Java Thread yield

Currently running thread goes back to its runnable state (so it’s ready to run again, but is currently not running), so other threads have a chance to run. It’s only a hint for the thread scheduler (it can be ignored), so the given behavior (goin back to runnable state) is not guaranteed.


Java Thread Join
Java Thread join method can be used to pause the current thread execution until unless the specified thread is dead.public final void join(): This java thread join method puts the current thread on wait until the thread on which it’s called is dead. If the thread is interrupted, it throws InterruptedException.


public class ThreadJoinExample {

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyRunnable(), "t1");
        Thread t2 = new Thread(new MyRunnable(), "t2");
        Thread t3 = new Thread(new MyRunnable(), "t3");
        
        t1.start();
        
        //start second thread after waiting for 2 seconds or if it's dead
        try {
            t1.join(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        t2.start();
        
        //start third thread only when first thread is dead
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        t3.start();
        
        //let all threads finish execution before finishing main thread
        try {
            t1.join();
            t2.join();
            t3.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        System.out.println("All threads are dead, exiting main thread");
    }

}

class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println("Thread started:::"+Thread.currentThread().getName());
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread ended:::"+Thread.currentThread().getName());
    }
    
}
Output of the above program is:
Thread started:::t1
Thread started:::t2
Thread ended:::t1
Thread started:::t3
Thread ended:::t2
Thread ended:::t3
All threads are dead, exiting main thread


Java Thread wait, notify, notifyAll

Inter-thread communication or Co-operation is all about allowing synchronized threads to communicate with each other.
Cooperation (Inter-thread communication) is a mechanism in which a thread is paused running in its critical section and another thread is allowed to enter (or lock) in the same critical section to be executed.It is implemented by following methods of Object class:
  • wait()
  • notify()
  • notifyAll()


wait

Object wait methods has three variance, one which waits indefinitely for any other thread to call notify or notifyAll method on the object to wake up the current thread. Other two variances puts the current thread in wait for specific amount of time before they wake up.

notify

notify method wakes up only one thread waiting on the object and that thread starts execution. So if there are multiple threads waiting for an object, this method will wake up only one of them. The choice of the thread to wake depends on the OS implementation of thread management.

notifyAll

notifyAll method wakes up all the threads waiting on the object, although which one will process first depends on the OS implementation.
Example 
  1. class Customer{  
  2. int amount=10000;  
  3.   
  4. synchronized void withdraw(int amount){  
  5. System.out.println("going to withdraw...");  
  6.   
  7. if(this.amount<amount){  
  8. System.out.println("Less balance; waiting for deposit...");  
  9. try{wait();}catch(Exception e){}  
  10. }  
  11. this.amount-=amount;  
  12. System.out.println("withdraw completed...");  
  13. }  
  14.   
  15. synchronized void deposit(int amount){  
  16. System.out.println("going to deposit...");  
  17. this.amount+=amount;  
  18. System.out.println("deposit completed... ");  
  19. notify();  
  20. }  
  21. }  
  22.   
  23. class Test{  
  24. public static void main(String args[]){  
  25. final Customer c=new Customer();  
  26. new Thread(){  
  27. public void run(){c.withdraw(15000);}  
  28. }.start();  
  29. new Thread(){  
  30. public void run(){c.deposit(10000);}  
  31. }.start();  
  32.   
  33. }}  
Output: going to withdraw...
       Less balance; waiting for deposit...
       going to deposit...
       deposit completed...
       withdraw completed

Example: Producer Consumer Problem


Key Points -:

  • You need to call wait() method on the object which is shared between two threads, in producer-consumer problem its the queue which is shared between producer and consumer threads.
  • The second confusion comes from the fact that wait needs to be a call from synchronized block or method? So if you use synchronized block, which object should be put to go inside the block? This should be the same object, whose lock you want to acquire i.e. the shared object between multiple threads. In our case it's queue.
  • Once you know that you need to call wait from synchronized context and on the shared object, next thing is to avoid mistake made by several Java developer by calling wait()method inside if block instead of while loop.
Based upon above knowledge here is  the standard code template or idiom to call wait and notify method in Java :

// The standard idiom for calling the wait method in Java
synchronized (sharedObject) {
   while (condition) {
      sharedObject.wait(); // (Releases lock, and reacquires on wakeup)
   }
   ... // do action based upon condition e.g. take or put into queue
}

As I suggested, you should always invoke wait method from a loop. The loop is used to test the condition before and after waiting. If the condition still holds and the notify (or notifyAll) method has already been invoked before a thread calls wait() method, then there is no guarantee that the thread will ever awake from the wait, potentially causing a deadlock.

Things to Remember about Using wait(), notify() and notifyAll() method 

  1. You can use wait() and notify() method to implement inter-thread communication in Java. Not just one or two threads but multiple threads can communicate to each other by using these methods.
  2. Always call wait()notify() and notifyAll() methods from synchronized method or synchronized block otherwise JVM will throw IllegalMonitorStateException.
  3. Always call wait and notify method from a loop and never from if() block, because loop test waiting condition before and after sleeping and handles notification even if waiting for the condition is not changed.
  4. Always call wait in shared object e.g. shared queue in this example.
  5. Prefer notifyAll() over notify() method due to reasons given in this article. 

Producer Consumer problem:





Synchronization
Synchronization in Java is an important concept since Java is a multi-threaded language where multiple threads run in parallel to complete program execution. In multi-threaded environment synchronization of Java object or synchronization of Java class becomes extremely important. Synchronization in Java is possible by using Java keywords "synchronized" and "volatile”.

Concurrent access of shared objects in Java introduces to kind of errors: thread interference and memory consistency errors and to avoid these errors you need to properly synchronize your Java object to allow mutual exclusive access of critical section to two threads.
  • Java synchronization works on locking and unlocking of resource, before any thread enters into synchronized code, it has to acquire lock on the Object and when code execution ends, it unlocks the resource that can be locked by other threads. In the mean time other threads are in wait state to lock the synchronized resource.
  • We can use synchronized keyword in two ways, one is to make a complete method synchronized and other way is to create synchronized block.
  • When a method is synchronized, it locks the Object, if method is static it locks the Class, so it's always best practice to use synchronized block to lock the only sections of method that needs synchronization.
  • While creating synchronized block, we need to provide the resource on which lock will be acquired, it can be XYZ.class or any Object field of the class.
  • synchronized(this) will lock the Object before entering into the synchronized block.
  • You should use the lowest level of locking, for example if there are multiple synchronized block in a class and one of them is locking the Object, then other synchronized blocks will also be not available for execution by other threads. When we lock an Object, it acquires lock on all the fields of the Object.
  • Java Synchronization provides data integrity on the cost of performance, so it should be used only when it's absolutely necessary.

Volatile

Volatile keyword in Java is used as an indicator to Java compiler and Thread that do not cache value of this variable and always read it from main memory. So if you want to share any variable in which read and write operation is atomic by implementation e.g. read and write in an int or a boolean variable then you can declare them as volatile variable.

Reflection

Java Reflection is a process of examining or modifying the run time behavior of a class at run time.
The java.lang.Class class provides many methods that can be used to get metadata, examine and change the run time behavior of a class.
The java.lang and java.lang.reflect packages provide classes for java reflection.

There are 3 ways to get the instance of Class class. They are as follows:
  • forName() method of Class class
  • getClass() method of Object class
  • the .class syntax

Typical ways Of Object creation

  • Using new operator - new xyzClass()
  • Using factory methods - xyzFactory.getInstance( )
  • Using newInstance( ) method - (Class.forName(xyzClass))emp.newInstance( )
  • By cloning an already available object - (xyzClass)obj1.clone( )

Fail Fast Vs Fail Safe Iterators In Java :


Fail-Fast IteratorsFail-Safe Iterators
Fail-Fast iterators doesn’t allow modifications of a collection while iterating over it.Fail-Safe iterators allow modifications of a collection while iterating over it.
These iterators throw ConcurrentModificationException if a collection is modified while iterating over it.These iterators don’t throw any exceptions if a collection is modified while iterating over it.
They use original collection to traverse over the elements of the collection.They use copy of the original collection to traverse over the elements of the collection.
These iterators don’t require extra memory.These iterators require extra memory to clone the collection.
Ex : Iterators returned by ArrayListVectorHashMap.Ex : Iterator returned by ConcurrentHashMap.
Deep cloning and Shallow cloning

What is Shallow Copy?
Shallow copy is a bit-wise copy of an object. A new object is created that has an exact copy of the values in the original object. If any of the fields of the object are references to other objects, just the reference addresses are copied i.e., only the memory address is copied.
Shallow Copy
In this figure, the MainObject1 have fields "field1" of int type, and "ContainObject1" of ContainObject type. When you do a shallow copy of MainObject1, MainObject2 is created with "field2" containing the copied value of "field1" and still pointing to ContainObject1 itself. Observe here and you will find that since field1 is of primitive type, the values of it are copied to field3 but ContainedObject1 is an object, so MainObject2 is still pointing to ContainObject1. So any changes made to ContainObject1 in MainObject1 will reflect in MainObject2.
Now if this is shallow copy, lets see what's deep copy?
What is Deep Copy?
A deep copy copies all fields, and makes copies of dynamically allocated memory pointed to by the fields. A deep copy occurs when an object is copied along with the objects to which it refers.
Deep Copy
In this figure, the MainObject1 have fields "field1" of int type, and "ContainObject1" of ContainObject type. When you do a deep copy of MainObject1, MainObject2 is created with "field3" containing the copied value of "field1" and "ContainObject2" containing the copied value of ContainObject1.So any changes made to ContainObject1 in MainObject1 will not reflect in MainObject2.

Well, here we are with what shallow copy and deep copy are and obviously the difference between them. Now lets see how to implement them in java.
How to implement shallow copy in java?
Here is an example of Shallow Copy implementation
class Subject {

  private String name;

  public String getName() {
    return name;
  }

  public void setName(String s) {
    name = s;
  }

  public Subject(String s) {
    name = s;
  }
}

class Student implements Cloneable {
  //Contained object
  private Subject subj;

  private String name;

  public Subject getSubj() {
 return subj;
  }

  public String getName() {
 return name;
  }

  public void setName(String s) {
 name = s;
  }

  public Student(String s, String sub) {
 name = s;
 subj = new Subject(sub);
  }

  public Object clone() {
 //shallow copy
 try {
   return super.clone();
 } catch (CloneNotSupportedException e) {
   return null;
 }
  }
}

public class CopyTest {

  public static void main(String[] args) {
 //Original Object
 Student stud = new Student("John", "Algebra");

 System.out.println("Original Object: " + stud.getName() + " - "
  + stud.getSubj().getName());

 //Clone Object
 Student clonedStud = (Student) stud.clone();

 System.out.println("Cloned Object: " + clonedStud.getName() + " - "
  + clonedStud.getSubj().getName());

 stud.setName("Dan");
 stud.getSubj().setName("Physics");

 System.out.println("Original Object after it is updated: " 
  + stud.getName() + " - " + stud.getSubj().getName());

 System.out.println("Cloned Object after updating original object: "
  + clonedStud.getName() + " - " + clonedStud.getSubj().getName());

  }
}

Output is:
Original Object: John - Algebra
Cloned Object: John - Algebra
Original Object after it is updated: Dan - Physics
Cloned Object after updating original object: John - Physics

In this example, all I did is, implement the class that you want to copy with Clonable interface and override clone() method of Object class and call super.clone() in it. If you observe, the changes made to "name" field of original object (Student class) is not reflected in cloned object but the changes made to "name" field of contained object (Subject class) is reflected in cloned object. This is because the cloned object carries the memory address of the Subject object but not the actual values. Hence any updates on the Subject object in Original object will reflect in Cloned object.

How to implement deep copy in java?
Here is an example of Deep Copy implementation. This is the same example of Shallow Copy implementation and hence I didnt write the Subject and CopyTest classes as there is no change in them.
class Student implements Cloneable {
  //Contained object
  private Subject subj;

  private String name;

  public Subject getSubj() {
 return subj;
  }

  public String getName() {
 return name;
  }

  public void setName(String s) {
 name = s;
  }

  public Student(String s, String sub) {
 name = s;
 subj = new Subject(sub);
  }

  public Object clone() {
 //Deep copy
 Student s = new Student(name, subj.getName());
 return s;
  }
}

Output is:
Original Object: John - Algebra
Cloned Object: John - Algebra
Original Object after it is updated: Dan - Physics
Cloned Object after updating original object: John - Algebra



Another Explanation

Shallow Copy

Generally clone method of an object, creates a new instance of the same class and copies all the fields to the new instance and returns it. This is nothing but shallow copy. Object class provides a clone method and provides support for the shallow copy. It returns ‘Object’ as type and you need to explicitly cast back to your original object.
Since the Object class has the clone method (protected) you cannot use it in all your classes. The class which you want to be cloned should implement clone method and overwrite it. It should provide its own meaning for copy or to the least it should invoke the super.clone(). Also you have to implement Cloneable marker interface or else you will get CloneNotSupportedException. When you invoke the super.clone() then you are dependent on the Object class’s implementation and what you get is a shallow copy.

Deep Copy

When you need a deep copy then you need to implement it yourself. When the copied object contains some other object its references are copied recursively in deep copy. When you implement deep copy be careful as you might fall for cyclic dependencies. If you don’t want to implement deep copy yourselves then you can go for serialization. It does implements deep copy implicitly and gracefully handling cyclic dependencies

Lazy Copy

A lazy copy is a combination of both shallow copy and deep copy. When initially copying an object, a (fast) shallow copy is used. A counter is also used to track how many objects share the data. When the program wants to modify the original object, it can determine if the data is shared (by examining the counter) and can do a deep copy at that time if necessary.


Garbage Collector

Garbage collection is an automatic process in Java which relieves the programmer of object memory allocation and de-allocation chores. 
Java has four types of garbage collectors,
  1. Serial Garbage Collector
  2. Parallel Garbage Collector
  3. CMS Garbage Collector
  4. G1 Garbage Collector

1. Serial Garbage Collector

Serial garbage collector works by holding all the application threads. It is designed for the single-threaded environments. It uses just a single thread for garbage collection. The way it works by freezing all the application threads while doing garbage collection may not be suitable for a server environment. It is best suited for simple command-line programs.
Turn on the -XX:+UseSerialGC JVM argument to use the serial garbage collector.

2. Parallel Garbage Collector

Parallel garbage collector is also called as throughput collector. It is the default garbage collector of the JVM. Unlike serial garbage collector, this uses multiple threads for garbage collection. Similar to serial garbage collector this also freezes all the application threads while performing garbage collection.

3. CMS Garbage Collector

Concurrent Mark Sweep (CMS) garbage collector uses multiple threads to scan the heap memory to mark instances for eviction and then sweep the marked instances. CMS garbage collector holds all the application threads in the following two scenarios only,
  1. while marking the referenced objects in the tenured generation space.
  2. if there is a change in heap memory in parallel while doing the garbage collection.
In comparison with parallel garbage collector, CMS collector uses more CPU to ensure better application throughput. If we can allocate more CPU for better performance then CMS garbage collector is the preferred choice over the parallel collector.
Turn on the XX:+USeParNewGC JVM argument to use the CMS garbage collector.

4. G1 Garbage Collector

G1 garbage collector is used for large heap memory areas. It separates the heap memory into regions and does collection within them in parallel. G1 also does compacts the free heap space on the go just after reclaiming the memory. But CMS garbage collector compacts the memory on stop the world (STW) situations. G1 collector prioritizes the region based on most garbage first.
Turn on the –XX:+UseG1GC JVM argument to use the G1 garbage collector.




Garbage Collection JVM Options

Following are the key JVM options that are related to Java garbage collection.

Type of Garbage Collector to run

OptionDescription
-XX:+UseSerialGCSerial Garbage Collector
-XX:+UseParallelGCParallel Garbage Collector
-XX:+UseConcMarkSweepGCCMS Garbage Collector
-XX:ParallelCMSThreads=CMS Collector – number of threads to use
-XX:+UseG1GCG1 Gargbage Collector

Important Points of Garbage Collector

1) Objects are created on the heap in Java irrespective of their scope e.g. local or member variable. while it's worth noting that class variables or static members are created in method area of Java memory space and both heap and method area is shared between different thread.

2) Garbage collection is a mechanism provided by Java Virtual Machine to reclaim heap space from objects which are eligible for Garbage collection.

3) Garbage collection relieves Java programmer from memory management which is an essential part of C++ programming and gives more time to focus on business logic.

4) Garbage Collection in Java is carried by a daemon thread called Garbage Collector.

5) Before removing an object from memory garbage collection thread invokes finalize()method of that object and gives an opportunity to perform any sort of cleanup required.

6) You as Java programmer can not force garbage collection in Java; it will only trigger if JVM thinks it needs a garbage collection based on Java heap size.

7) There are methods like System.gc() and Runtime.gc() which is used to send request of Garbage collection to JVM but it’s not guaranteed that garbage collection will happen.

8) If there is no memory space for creating a new object in Heap Java Virtual Machine throws OutOfMemoryError or java.lang.OutOfMemoryError heap space

9) J2SE 5(Java 2 Standard Edition) adds a new feature called Ergonomics goal of ergonomics is to provide good performance from the JVM with a minimum of command line tuning. See Java Performance The Definitive Guide for more details on garbage collection tuning.


http://javapapers.com/java/types-of-java-garbage-collectors/

Interview Prep: Java full stack

 SOLID principle :  https://www.educative.io/answers/what-are-the-solid-principles-in-java Design Pattern:  Creational:  https://medium.com...