Java Concurrency
Java Concurrency
1. Safety Issues
Definition: Safety ensures that concurrent threads do not produce incorrect results or leave the
program in an invalid state. It typically arises due to improper synchronization.
Examples:
Race Conditions: Two or more threads access shared data at the same time, and at least
one thread modifies the data, causing unpredictable results.
Data Inconsistency: Improper synchronization leads to shared data being corrupted.
Solutions:
2. Liveness Issues
Definition: Liveness refers to the system's ability to make progress. Problems arise when threads
cannot proceed with their tasks.
Examples:
Deadlock: Two or more threads are waiting for each other's locks, causing an indefinite
halt.
Starvation: A thread is perpetually denied access to resources due to other high-priority
threads.
Blocked Threads: A thread is stuck waiting for a condition that will never be met.
Solutions:
Avoid nested locks or use a consistent lock acquisition order to prevent deadlocks.
Use ReentrantLock with fairness policies.
Implement timeouts using methods like tryLock() from ReentrantLock.
3. Fairness Issues
Definition: Fairness ensures that all threads get an opportunity to execute without being starved
by other threads.
Examples:
Unfair Scheduling: Threads with lower priority or those that have waited longer may be
ignored in favor of others.
Thread Starvation: When certain threads are perpetually denied CPU time or access to
resources.
Solutions:
Use ReentrantLock with the fairness flag set to true. For example:
java
Copy code
Lock lock = new ReentrantLock(true); // Fair lock
By addressing safety, liveness, and fairness, you can build robust and efficient concurrent
applications in Java.
In Java, locks are mechanisms used to ensure that multiple threads do not access shared
resources concurrently in a way that causes conflicts or inconsistencies. Java provides several
ways to use locks, from basic synchronization primitives to advanced locking mechanisms in the
java.util.concurrent package.
Every Java object has an intrinsic lock, which can be accessed via the synchronized
keyword.
Usage:
o Synchronize a method:
java
Copy code
public synchronized void sharedMethod() {
// Critical section
}
o Synchronize a block:
java
Copy code
public void sharedMethod() {
synchronized(this) {
// Critical section
}
}
Features:
o Simple to use.
o Automatically releases the lock when the thread exits the synchronized block.
o Does not allow try-locking or fairness policies.
java
Copy code
import java.util.concurrent.locks.ReentrantLock;
java
Copy code
if (lock.tryLock()) {
try {
// Critical section
} finally {
lock.unlock();
}
} else {
// Handle the case where the lock was not acquired
}
o Supports fair locks: Threads are granted locks in the order they requested.
java
Copy code
ReentrantLock fairLock = new ReentrantLock(true); // Fair policy
Reentrancy
A thread that already holds a lock can reacquire it without causing a deadlock.
Example: Both synchronized and ReentrantLock are reentrant.
Fairness
Interruptible Locks
1. ReadWriteLock
o Provides a pair of locks: one for reading and one for writing.
o Multiple threads can hold the read lock simultaneously, but the write lock is
exclusive.
o Example:
java
Copy code
import java.util.concurrent.locks.ReentrantReadWriteLock;
2. StampedLock
o More lightweight and optimized compared to ReadWriteLock.
o Provides read, write, and optimistic read locks for better performance in read-
heavy scenarios.
3. Semaphore
o Limits access to a resource to a fixed number of threads.
java
Copy code
Semaphore semaphore = new Semaphore(3); // 3 permits
4. CountDownLatch
o Blocks threads until a certain number of signals or events occur.
5. CyclicBarrier
o Allows multiple threads to wait at a barrier point before all threads proceed.
When to Use Which Lock
By understanding and using locks effectively, you can create thread-safe and efficient concurrent
applications in Java.