Interview questions on Java Collections Framework and concurrency — among the most frequently tested topics in Java interviews.

Collections Framework

Q: ArrayList vs LinkedList?

ArrayList LinkedList
Internal Dynamic array Doubly linked list
Random access O(1) O(n)
Insert/delete at end O(1) amortized O(1)
Insert/delete at middle O(n) O(1) with iterator
Memory Less overhead More (node pointers)
Best for Frequent reads Frequent insert/delete

Q: HashMap internal working?

  put(key, value):
  1. hash = key.hashCode() ^ (hash >>> 16)
  2. index = hash & (capacity - 1)
  3. If bucket empty → insert
  4. If bucket occupied → check equals()
     - Same key → replace value
     - Different key → add to linked list / tree (if > 8 nodes)
  5. If size > threshold → resize (double capacity)
  

Since Java 8: buckets with >8 nodes convert to red-black tree (O(log n) worst case).

Q: HashMap vs ConcurrentHashMap?

HashMap ConcurrentHashMap
Thread-safe No Yes
Null keys/values Allowed Not allowed
Iteration Fail-fast Weakly consistent
Locking None Segment/CAS-based
Performance Fastest (single thread) Good under contention

Q: fail-fast vs fail-safe iterators?

  // fail-fast (ArrayList, HashMap) — throws ConcurrentModificationException
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
for (String s : list) {
    list.remove(s);  // ConcurrentModificationException!
}

// fail-safe (CopyOnWriteArrayList, ConcurrentHashMap) — iterates snapshot
List<String> safe = new CopyOnWriteArrayList<>(List.of("a", "b", "c"));
for (String s : safe) {
    safe.remove(s);  // OK — operates on copy
}
  

Concurrency

Q: Thread vs Runnable vs Callable?

Thread Runnable Callable
Return value No No Yes (V)
Exception Unchecked only Unchecked only Checked allowed
Reuse No (1:1) Yes (ExecutorService) Yes
Usage Avoid extending Thread Preferred When return value needed
  ExecutorService pool = Executors.newFixedThreadPool(4);
Future<Integer> future = pool.submit(() -> computeResult());
Integer result = future.get(5, TimeUnit.SECONDS);
pool.shutdown();
  

Q: synchronized vs ReentrantLock?

synchronized ReentrantLock
Syntax Built-in keyword Explicit lock/unlock
Release Automatic Manual (must unlock in finally)
Fairness Non-fair default Configurable fair/non-fair
Features Basic tryLock, timeout, conditions
Performance Optimized (biased locking) Slightly more overhead

Q: volatile keyword?

Guarantees visibility (not atomicity):

  private volatile boolean running = true;

// Thread 1
running = false;  // immediately visible to Thread 2

// Thread 2
while (running) { /* work */ }  // sees false, exits loop
  

Use for: flags, single-writer scenarios. For compound operations, use AtomicInteger or synchronized.

Q: Explain thread pool parameters.

  ThreadPoolExecutor executor = new ThreadPoolExecutor(
    4,                      // corePoolSize
    8,                      // maximumPoolSize
    60, TimeUnit.SECONDS,   // keepAliveTime
    new ArrayBlockingQueue<>(100),  // workQueue
    new ThreadPoolExecutor.CallerRunsPolicy()  // rejection policy
);
  

Execution order: core threads → queue → extra threads → rejection policy.

Q: Deadlock — how to detect and prevent?

Detection: thread dump (jstack) shows “Found one Java-level deadlock”.

Prevention:

  1. Lock ordering — always acquire locks in same order
  2. Lock timeout — tryLock(timeout)
  3. Avoid nested locks
  4. Use concurrent collections instead of manual locking

Coding Questions

Q: Implement a thread-safe singleton.

  public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
  

Or use enum (best approach):

  public enum Singleton {
    INSTANCE;
    public void doWork() { /* ... */ }
}
  

Q: Print numbers 1-100 alternately with two threads.

  Object lock = new Object();
IntSupplier printer = () -> {
    for (int i = 1; i <= 100; i += 2) {
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
            lock.notify();
            try { lock.wait(); } catch (InterruptedException e) { break; }
        }
    }
};
new Thread(printer::getAsInt, "Odd").start();
new Thread(() -> { /* even numbers */ }, "Even").start();