JVM AND Core Java

Very Important INTERVIEW_QUESTIONS

Source: Converted from the uploaded JVM_Details.htm while preserving the source document's terminology, questions, tables and diagrams.

JVM

The Java Virtual Machine (JVM) memory model is a crucial concept for understanding how Java applications run. It manages memory in several distinct regions, each serving a specific purpose. Here's an overview of the key memory areas: Heap , Stack , and Metaspace .

+------------------------------+
|
    

Method Area (
Metaspace
) |
+------------------------------+
|
         

Heap
               
|
+------------------------------+
|
         

Stack
              
|
+------------------------------+
|
    

Program Counter (
PC)
  

 
|
+------------------------------+
|
    

Native Method Stack
     
|
+------------------------------+

JVM Memory Areas Recap:

AreaDescription
HeapStores objects and class instances.
StackStores method frames, local variables.
Metaspace (Java 8+)Stores class metadata, static methods, and constants.
Method Area (part of Metaspace )Stores class-level data like static variables, method info, and the string constant pool.

JVM Memory Diagram (Java 8+)

+----------------------------------------------+
|
                  
JVM Memory
                  
|
+----------------------+-----------------------+
|
    

Heap
             
|
     
Metaspace
         
|
| (for 
objects)
   
     
|
  
(
replaces 
PermGen
)
   
|
|
                      
|
                       
|
|
 

+---------------+
   
|
  
+-----------------+
  
|
|
  
|
 String
Objects|
   
|
  
|
 String Constant 
|
  
|
|
  
|
 (e.g.,
new
    
|
  

|
  
|
     
Pool
       

|
  
|
|
  
|
  
String("a")) |
   
|
  
|
 ("a", "b", 
etc
) 
|
 

|
|
 

+---------------+
   
|
  
+-----------------+
  
|
|
                      
|
                       
|
|
                      
|
  
+-----------------+
  
|
|
                      
|
  
|
 Static final
     
| |
|
                      
|
  
|
 constants
        
| |
|
                      
|
  
|
 (e.g. int MAX = 5| |
|
                      
|
  
|
 

if 
inlined
)
   
  
| |
|
                      
|
  
+-----------------+
  
|
+----------------------+-----------------------+

JVM Memory Diagram (Java 8+)

+---------------------------+
|
       
Java Thread
         
|
|
  
(
java.lang
.Thread
 class) |
+---------------------------+
             
|
             
V
+---------------------------+
|
    
JVM Thread Structure
   
|
|
  
-
 Java
Stack
             
|
|
  
-
 Native
Stack
           
|
|
  
-
 Program
Counter
        
|
|
  
-
 Thread
ID
              
|
+---------------------------+
             
|
             
V
+---------------------------+
|
     
OS-Level Thread
       
|
|
  
(
pthread
 / Windows 
API)
  
|
+---------------------------+

Garbage Collection algorithms in Java

GC AlgorithmPause TimeThroughputHeap Size SuitabilityMultithreadedConcurrency
SerialHighLowSmall❌ No❌ No
ParallelMediumHighMedium to Large✅ Yes❌ No
CMSLowMediumMedium✅ Yes✅ Partial
G1Low-MediumHighMedium to Large✅ Yes✅ Partial
ZGCVery LowHighHuge (>1TB)✅ Yes✅ Full
ShenandoahVery LowHighLarge✅ Yes✅ Full

JVM options for GC logging:

-
Xlog:gc
*
-
XX:+
PrintGCDetails
-
XX:+
PrintGCDateStamps

What are the best practices for designing immutable classes?

PrincipleBenefit
Final classPrevents subclass modification
Private final fieldsPrevents field mutation
Constructor initializationFull object initialization
No settersEnsures immutability
Defensive copiesAvoid shared mutable state
Immutable data structuresSafer multithreaded use

How does synchronized, ReentrantLock , ExecutorService work?

FeaturesynchronizedReentrantLockExecutorService
Locking TypeIntrinsic (object/class)Explicit (manual control)Task Execution & Thread Management
Unlock RequirementAutomaticManual ( unlock( ))Not applicable
FairnessNoOptional (new ReentrantLock (true))Depends on pool
Try Lock / TimeoutNoYes ( tryLock ( ), tryLock (timeout))Not applicable
InterruptibleNoYesYes (task cancellation APIs)
Use CaseSimple lockingComplex locking scenariosAsync task execution

How is HashMap works internally/implemented

StepDescription
1️ ⃣When you put a key-value pair, the key’s hashCode ( ) is calculated.
2️ ⃣That hashCode is used to compute the index (bucket) using index = hash % capacity.
3️ ⃣If the bucket is empty, the new node is stored directly.
4️ ⃣If the bucket already has a node, equals( ) is used to check for duplicates.
5️ ⃣If equals( ) returns true, value is updated; otherwise, a new node is added to the chain (linked list or tree).
6️ ⃣When a bucket’s chain becomes too long (threshold = 8), it's converted into a TreeNode (Red-Black Tree) for faster access.
7️ ⃣When you call get(key), it computes the hashCode ( ) and index, then finds the node by checking keys with equals( ).
8️ ⃣If key found ➝ returns value, else ➝ returns null.
9️ ⃣HashMap resizes (doubles capacity) when the size exceeds threshold = capacity * loadFactor . Default load factor = 0.75.

How is ConcurrentHashMap implemented?

ConcurrentHashMap is a thread-safe and highly concurrent implementation of a hash map in Java. It allows multiple threads to read and write without locking the entire map.

StepDescription
1️ ⃣ConcurrentHashMap uses segments internally in Java 7 , but buckets with Node arrays + CAS locking in Java 8+.
2️ ⃣When inserting ( put( )), the key’s hashCode ( ) is computed to determine the bucket index.
3️ ⃣If the bucket is empty , a new node is inserted using CAS (Compare-And-Swap) to ensure thread-safety.
4️ ⃣If the bucket is not empty , threads use fine-grained locking only on that particular bucket/node.
5️ ⃣If multiple threads try to write to the same bucket , only one thread locks that bucket — not the entire map.
6️ ⃣If hash collisions occur, nodes are stored in a linked list , and converted to tree nodes (like HashMap) if they grow beyond threshold (8).
7️ ⃣For reads ( get( )), it uses volatile reads , so it’s mostly lock-free — giving excellent performance.
8️ ⃣Resizing is thread-safe and done using transfer bins where threads help in rehashing

What is the difference between HashMap and ConcurrentHashMap ?

ü HashMap is not thread-safe and may produce inconsistent results in multithreaded environments.

ü ConcurrentHashMap allows concurrent access with thread safety using internal segment locking.

Thread Safety

A thread-safe class or method ensures that shared data is accessed and modified in a controlled and predictable manner . If two or more threads use it simultaneously, it will function correctly without needing additional synchronization from the user.

TechniqueThread SafetyUse Case
synchronized✅ YesSimple critical section control
java.util .concurrent✅ YesCollections and utilities
Atomic variables✅ YesLock-free counters, flags
Immutable objects✅ YesData that never changes
Thread-local storage✅ YesPer-thread variable isolation
Locks ( ReentrantLock )✅ YesFine-grained locking, tryLock , fairness, etc.

ReentrantLock implements Lock

ü It is the implementation class of Lock interface and direct child class of object.

ü Reentrant means a thread can acquire same lock multiple times without any issue.

How would you implement a thread-safe LRU cache?

Implementing a thread-safe LRU (Least Recently Used) cache in Java can be done in several ways. Here's a breakdown of the most common and effective approach using:

Approach: Use LinkedHashMap with synchronization

ü LinkedHashMap maintains insertion/access order.

ü Override removeEldestEntry to implement LRU eviction.

ü Add synchronization or use Collections.synchronizedMap () or ReentrantReadWriteLock for thread safety.

Parallel streams

It make use of the fork-join framework and its common pool of worker threads.

CompletableFuture

It is a class in Java ( java.util .concurrent ) that allows you to write asynchronous , non-blocking code. It helps you run tasks in the background and then continue processing once they’re complete.

Rich async composition, chaining, non-blocking where as feature java5 feature and it will perform Simple async task with blocking result

CompletableFuture is part of java.util .concurrent that represents a future result of an asynchronous computation.

StepWhat Happens
1️ ⃣You call an async method like supplyAsync ( ) or runAsync ( ) to start work in the background.
2️ ⃣Java spawns a new thread (from ForkJoinPool or custom executor).
3️ ⃣When the task is done, CompletableFuture is completed with a result or an exception.
4️ ⃣You can attach callbacks like . thenApply () , . thenAccept () , . thenRun () to chain further actions.
5️ ⃣You can also combine multiple futures using . thenCombine () , . allOf () , . anyOf (), etc.
6️ ⃣Finally, you can block using .get () (if needed) or handle exceptions using .exceptionally ().

Explain memory leaks in Java. How do you detect and fix them?

ü Memory leaks happen when objects are no longer in use but are still referenced.

ü Tools: VisualVM , Eclipse MAT, JProfiler .

ü Common causes: static collections, listeners not removed, inner classes holding outer class references.

ü Fix: Ensure objects are dereferenced properly, use WeakReference when appropriate.

Bestways to use Concurrency in Java:

1. Use Modern Java Concurrency APIs (Avoid Thread and synchronized)

2. Prefer ForkJoinPool for Parallel Processing

3. Use CompletableFuture for Asynchronous Programming

4. Avoid Race Conditions with Atomic Variables or Locks

5. Avoid Deadlocks by Lock Ordering

6. Use ThreadLocal for Thread-Specific Data

7. Use ScheduledExecutorService for Periodic Tasks

8. Use Non-Blocking I/O (NIO) for High-Performance Applications

9. Prefer Virtual Threads (Java 21) Over Traditional Threads

10. Monitor and Tune Thread Performance