Govt Exams
This is a classic deadlock scenario involving circular wait. Race condition involves competing for resources. Starvation is when a thread never gets the resource. Livelock is when threads keep changing states without progress.
ConcurrentHashMap uses segment-based locking (in older versions) or fine-grained locking to provide thread-safety without synchronizing the entire map. Other options require external synchronization or Collections.synchronizedMap().
When wait() is called, the thread releases the lock it holds on the object and enters the waiting pool. Another thread can then acquire the lock. The thread re-acquires the lock when notified.
CyclicBarrier is a synchronizer that allows a fixed number of threads to wait for each other at a barrier point. Once all threads reach the barrier, they proceed together. It's reusable (cyclic) unlike CountDownLatch.
notify() randomly selects one waiting thread to wake up, while notifyAll() wakes all waiting threads. notifyAll() is generally safer to avoid missed notifications when multiple threads are waiting on the same condition.
Callable interface returns a result via Future, and ExecutorService.invokeAll() waits for all submitted tasks to complete. This is the standard pattern for parallel task execution with result collection.
Object lock = new Object();
synchronized(lock) {
synchronized(lock) {
System.out.println("Nested");
}
}
Java supports reentrant locks on synchronized blocks. The same thread can acquire the same lock multiple times. The lock is released only when the outermost synchronized block exits.
Java 21 introduced Virtual Threads as a lightweight threading model under Project Loom, allowing millions of concurrent tasks. This is more efficient than platform threads for high-concurrency scenarios.
Deadlock occurs when two or more threads are waiting indefinitely for locks held by each other. Option B creates a reentrant situation (allowed in ReentrantLock). Option C is problematic but not necessarily deadlock. Option D is safe if used properly.
The volatile keyword ensures that any read of a volatile variable will read the most recent write by any thread. It provides visibility guarantees but not atomicity, making it lighter than synchronization for simple flag checks.