-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
246: Common Java Interview Questions on Collections and Concurrency
Look, I've sat on both sides of the interview table. When an interviewer asks about Collections and Concurrency, they aren't just checking if you've memorized the API docs; they want to know if you understand how Java actually behaves when multiple threads start fighting over the same piece of memory. Here are the questions that usually trip people up and how I'd explain the answers.
Why bother with ConcurrentHashMap over a synchronized map?
If you're in an interview and they ask about thread-safe maps, don't just say "use a synchronized map." That's a rookie mistake. Collections.synchronizedMap() wraps the entire map in a single global lock. It's like having a massive library where only one person is allowed inside at a time, regardless of which book they want. It's safe, but it's a performance nightmare.
ConcurrentHashMap is smarter. It uses a technique called lock striping (or in newer Java versions, a mix of CAS operations and synchronized blocks on individual bucket nodes). It essentially breaks the map into segments so that multiple threads can write to different parts of the map simultaneously. If Thread A is updating a key in bucket 1, Thread B can still update a key in bucket 10 without waiting.
// This is the "slow" way - global lock Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>()); // This is the "pro" way - high concurrency Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();What's actually happening during a ConcurrentModificationException?
You've probably seen this error while trying to remove an item from a list while iterating over it. This is what we call a "fail-fast" iterator. The
ArrayListiterator keeps a internalmodCount. If the list is modified structurally while the iterator is active, the iterator sees that the count has changed and immediately throws the exception to prevent unpredictable behavior.Now, if you absolutely need to modify a list while iterating—say, you're cleaning up expired cache entries in a background thread—you have two real options. Use the
Iterator.remove()method, or switch to a "fail-safe" (or more accurately, weakly consistent) collection likeCopyOnWriteArrayList. The latter creates a fresh copy of the underlying array every time you modify it, so the iterator is just looking at a "snapshot" of the data from the moment it was created.// This will crash List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C")); for (String s : list) { if (s.equals("B")) list.remove(s); // Boom! ConcurrentModificationException } // This is safe because it works on a snapshot List<String> cowList = new CopyOnWriteArrayList<>(Arrays.asList("A", "B", "C")); for (String s : cowList) { if (s.equals("B")) cowList.remove(s); // Works fine }When should I use a Callable instead of a Runnable?
I like to think of a
Runnableas "fire and forget." You tell the thread to go do some work, and that's it. It can't return a value, and if it throws a checked exception, you have to handle it inside therun()method because the method signature doesn't allow it.A
Callable, on the other hand, is for when you actually need a result back. It returns aFuture. Imagine you're building a dashboard that needs to fetch data from three different APIs. You wouldn't useRunnable; you'd useCallableso you can wait for the results and then aggregate them.Callable<Integer> fetchPrice = () -> { // Simulate network delay Thread.sleep(1000); return 150; // Return a value! }; ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Integer> future = executor.submit(fetchPrice); // This blocks until the result is ready Integer price = future.get();Is the 'volatile' keyword enough to make a variable thread-safe?
Short answer: No. Long answer:
volatileonly solves the visibility problem, not the atomicity problem.In Java, threads often cache variables in CPU registers for performance. If Thread A updates a variable, Thread B might keep reading the old cached value. Marking a variable
volatiletells Java: "Don't cache this; always read and write directly to main memory."But here is the trap: if you do
count++on a volatile variable, you aren't doing one operation. You're doing three: read, increment, and write. If two threads do this at the exact same time, they might both read '5', both increment it to '6', and both write '6' back. You just lost an update. For that, you needAtomicIntegeror asynchronizedblock.
📋 Practical Task
Exercise: Building a Thread-Safe User Session Registry
You are tasked with creating a UserSessionRegistry that allows a high-traffic web server to track active users. The registry must support the following requirements:
- Concurrent Access: Multiple threads must be able to add and remove users simultaneously without locking the entire registry.
- Safe Cleanup: A background "cleanup" thread must be able to iterate through all active sessions and remove those that have expired without triggering a
ConcurrentModificationException. - Result Tracking: Implement a method that uses a
Callableto calculate the total number of active sessions across multiple distributed shards (simulated by summing a few different maps).
Your Task: Implement the UserSessionRegistry class. Choose the correct java.util.concurrent collection to store the sessions and use an ExecutorService to handle the Callable logic for the session count.
There are no comments for now.