Differentiate concurrency and parallelism
|
Concurrency |
Parallelism |
|
Multiple tasks interleaved |
Multiple tasks simultaneously |
|
Improves responsiveness |
Improves execution speed |
|
Single or multiple cores |
Requires multiple CPU cores |
|
Context switching involved |
Tasks execute concurrently |
|
Focuses on task management |
Focuses on task execution |
How to create a multiple Threads
Extend Thread class
Implement Runnable interface
Implement Callable interface
Use ExecutorService thread pool
Use CompletableFuture API
JVM
Each thread owns stack
Heap shared across threads
Program counter per thread
Monitors manage synchronization
JMM ensures memory visibility
Thread stack
- Stores method call frames
- Each thread owns one
- Holds local variables
- Tracks method execution
- Created with thread start
program counter
- Stores current instruction address
- Each thread owns one
- Tracks execution progress
- Updated after every instruction
- Enables thread context switching
Volatile Keyword :
Ensures variable visibility always
Reads latest memory value
Prevents instruction reordering
Doesn't guarantee atomicity
No mutual exclusion provided
Problems with volatile
- No atomicity for operations
count++ involves read → modify → write, so multiple CPUs can overwrite each other's updates even though the variable is volatile. - Cache coherence overhead
Every volatile write invalidates cached copies in other CPU cores, increasing cache traffic and reducing performance. - Memory fence overhead
volatile inserts CPU memory barriers (fences), preventing instruction reordering and slowing execution. - No mutual exclusion
Multiple CPU cores can still execute the same code simultaneously; volatile only guarantees visibility, not exclusive access. - Not suitable for compound operations
Operations like increment, check-then-act, or read-modify-write require synchronization or atomic classes because volatile cannot prevent race conditions.
synchronized
- Provides mutual exclusion
- Uses object or class monitor
- Automatically releases lock
- Prevents race conditions
- Ensures memory visibility
wait()
- Releases object's monitor lock
- Thread enters waiting state
- Waits until notification
- Must own monitor
- Called inside synchronized
notify()
- Wakes one waiting thread
- Doesn't release lock immediately
- Must own monitor
- Called inside synchronized
- Thread competes for lock
How can deadlock happen
- Competing resource acquisition order
- Each thread holds lock
- Waiting for another lock
- Circular dependency between threads
- No thread can proceed
Class Lock
Locks entire class object
Shared across all instances
Acquired by static methods
Uses Class object monitor
One thread enters only
Object Lock
- Locks individual object instance
- Each object has monitor
- Acquired by synchronized methods
- Different objects lock independently
- One thread per object
Fail Fast vs Fail Safe Iterator
|
Fail-Fast Iterator |
Fail-Safe Iterator |
|
Iterates original collection |
Iterates collection snapshot |
|
Detects concurrent modifications |
Allows concurrent modifications |
|
Throws ConcurrentModificationException |
No ConcurrentModificationException |
|
Reflects latest collection state |
Reflects copied collection state |
|
Faster, lower memory overhead |
Slower, extra memory usage |
Examples:
- Fail-Fast: ArrayList, HashMap, HashSet
- Fail-Safe: ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentSkipListMap
Explain the differences between Deadlock and Livelock
|
Aspect |
Deadlock |
Livelock |
|
Definition |
Two or more threads are permanently blocked, each waiting for a resource held by another. |
Two or more threads keep changing state in response to each other but never make progress. |
|
Thread State |
Usually BLOCKED or WAITING. |
Usually RUNNABLE; threads are actively executing. |
|
CPU Usage |
Low (threads are blocked). |
High (threads keep running). |
|
Progress |
No progress because threads are waiting. |
No progress because threads keep retrying or yielding. |
|
Cause |
Circular resource dependency. |
Overly polite or repeated retry logic where threads continuously avoid each other. |
|
Example |
Thread A holds Lock1 and waits for Lock2, while Thread B holds Lock2 and waits for Lock1. |
Thread A releases a lock when it detects Thread B needs it, while Thread B does the same, causing both to endlessly back off. |
|
Detection |
Easy to detect using thread dumps (jstack), JVM deadlock detection, or VisualVM. |
Harder to detect because threads appear active. |
|
Resolution |
Use lock ordering, timeouts, avoid nested locks, or use tryLock(). |
Introduce random backoff, retry delays, or asymmetric retry strategies. |
How does ConcurrentHashMap achieve thread-safety ?
CAS for lock-free updates
Per-bucket synchronized locking
Volatile memory visibility guarantees
Atomic compound map operations
Concurrent reads without locking
Explain the differences between synchronized, ReentrantLock, and ReadWriteLock.
|
synchronized |
ReentrantLock |
ReadWriteLock |
|
JVM-managed intrinsic lock |
Explicit lock implementation |
Separate read/write locks |
|
Automatic lock release |
Manual unlock() required |
Manual unlock() required |
|
No fairness option |
Supports fair locking |
Supports fair locking |
|
No interruptible lock |
Interruptible lock acquisition |
Interruptible lock acquisition |
|
Exclusive access only |
Exclusive access only |
Concurrent readers allowed |
Differentiate between Runnable, Callable
|
Runnable |
Callable |
|
No return value |
Returns a value |
|
Cannot throw checked exceptions |
Can throw checked exceptions |
|
run() method |
call() method |
|
Used with Thread |
Used with ExecutorService |
|
Returns void |
Returns Future<T> |
Executor
- Executes submitted tasks
- Decouples task execution
- Abstracts thread management
- Uses thread pool implementations
- Improves resource utilization
ExecutorService
- Manages thread pool lifecycle
- Executes asynchronous tasks
- Returns Future results
- Supports graceful shutdown
- Reuses worker threads
Executors
- Factory for thread pools
- Creates ExecutorService instances
- Provides predefined pool types
- Simplifies thread pool creation
- Avoids manual configuration
ThreadPoolExecutor
- Manages reusable worker threads
- Executes submitted tasks efficiently
- Reduces thread creation overhead
- Supports configurable pool size
- Queues excess submitted tasks
Reenterant Lock
- Explicit lock implementation
- Supports lock reentrancy
- Requires manual unlock()
- Supports fair scheduling
- Provides interruptible locking
ReadWrite Lock
Separate read and write locks
Multiple readers access concurrently
Only one writer allowed
Writers block all readers
Improves read-heavy performance
Explain Compare and swap
- Atomic CPU instruction
- Compares expected memory value
- Updates if values match
- Retries when comparison fails
- Enables lock-free synchronisation
Future
- Represents asynchronous task result
- Retrieves result using get()
- Blocks until completion
- Supports task cancellation
- Cannot chain dependent tasks
Completion stage
- Represents asynchronous computation stage
- Depends on previous stage
- Chains multiple asynchronous operations
- Supports callback-based processing
- Implemented by CompletableFuture
completable future
- Implements Future<T> and CompletionStage<T>
- needs an ExecutorService because it does not create or manage its own threads
- Performs asynchronous computations
- Chains dependent asynchronous tasks
- Combines multiple task results
- Handles exceptions asynchronously
- Avoids blocking main thread
No comments:
Post a Comment