interview question of Java Backend
Interview Questions
Core Java (OOPs, Collections, Concurrency Basics)
Explain difference between HashMap, HashTable, and ConcurrentHashMap.
| Feature | HashMap | Hashtable | ConcurrentHashMap |
|---|---|---|---|
| Thread Safety | Not thread-safe | Thread-safe (synchronized methods) | Thread-safe (lock segmentation / fine-grained locking) |
| Null Keys/Values | Allows one null key and multiple null values | Does not allow any null keys/values | Does not allow null keys/values |
| Performance | Faster (no synchronization overhead) | Slower (entire table is locked) | Better concurrency — multiple threads can read/write different segments simultaneously |
| Use Case | Single-threaded apps | Legacy thread-safe code | High-performance concurrent apps |
Example:
If multiple threads are accessing and modifying a map, prefer ConcurrentHashMap. For non-concurrent cases, use HashMap. Avoid Hashtable in modern code.
How does equals() and hashCode() work together in collections?
- hashCode(): Returns an integer hash value used to place objects in hash-based collections (like HashMap, HashSet).
- equals(): Compares two objects for logical equality.
Contract:
- If two objects are equal according to equals(), they must have the same hashCode().
- If two objects have the same hashCode(), they may or may not be equal.
Why it matters:
Collections like HashMap use hashCode() to find a bucket, and then equals() to check if the key already exists.
Example:1
2
3
4
5
6
7
8
9
10
11
12
13
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person p = (Person) o;
return id == p.id;
}
public int hashCode() {
return Objects.hash(id);
}
Difference between shallow copy vs deep copy in Java.
| Type | Description | Example |
|---|---|---|
| Shallow Copy | Copies only object references (not the objects they refer to). Both objects share the same nested objects. | clone() without custom implementation |
| Deep Copy | Copies everything — including new instances of nested objects. Changes in one object don’t affect the other. | Implemented manually or via serialization |
Example:1
2
3
4
5
6// Shallow copy
Employee e2 = e1.clone(); // e1.address and e2.address point to same object
// Deep copy
Employee e2 = new Employee(e1);
e2.address = new Address(e1.address);
How do you prevent deadlock in multithreaded applications?
Deadlock occurs when two or more threads are waiting on each other’s locks.
Ways to prevent it:
- Lock ordering – Always acquire locks in a consistent order.
- Try-lock with timeout – Use tryLock() from ReentrantLock to avoid waiting forever.
- Avoid nested locks – Reduce code sections that acquire multiple locks.
- Use concurrent utilities – Prefer ConcurrentHashMap, BlockingQueue, etc., which manage synchronization internally.
- Minimize synchronized blocks – Keep critical sections small.
Example:1
2
3
4
5if (lock1.tryLock(50, TimeUnit.MILLISECONDS)) {
if (lock2.tryLock(50, TimeUnit.MILLISECONDS)) {
// work
}
}
Explain volatile vs synchronized — when to use each.
| Feature | volatile |
synchronized |
|---|---|---|
| Purpose | Guarantees visibility of changes across threads | Guarantees atomicity and visibility |
| Use Case | When multiple threads read/write a variable, and writes are independent | When operations on shared data must be atomic |
| Locking | No locking (lighter, faster) | Uses intrinsic lock (can block threads) |
| Scope | Variable-level only | Code block or method |
| Example Use | Status flags, configuration values | Counters, complex state updates |
Example:1
2
3
4
5volatile boolean running = true; // visibility only
synchronized void increment() { // atomic operation
count++;
}
Rule of thumb:
- Use volatile for simple flags or status updates.
- Use synchronized (or locks) for compound operations that must be atomic.




