๐ Understanding Java Concurrent Locks (java.util.concurrent.locks.Lock)
When writing multi-threaded programs in Java, thread safety becomes a key concern.
Traditionally, developers have used the synchronized keyword to protect critical sections.
However, Java’s java.util.concurrent.locks.Lock interface offers greater flexibility and control for concurrency management.
⚙️ What Is a Lock?
A Lock is a more advanced synchronization mechanism than the synchronized block.
It allows explicit acquisition and release of locks and supports features unavailable in synchronized blocks, such as:
-
Timed and interruptible lock acquisition,
-
Separate lock/unlock methods across scopes,
-
Fairness policies, and
-
Better performance in high-contention scenarios.
Since Lock is an interface, you must use one of its implementations —
most commonly ReentrantLock.
๐ Lock vs. synchronized — Key Differences
| Feature | synchronized | Lock (e.g., ReentrantLock) |
|---|---|---|
| Scope | Must be fully contained within one method or block | lock() and unlock() can be called in different methods |
| Timeout | Cannot wait with timeout | tryLock(long time, TimeUnit unit) allows timeout |
| Interruptibility | Cannot be interrupted while waiting | Lock acquisition can be interrupted |
| Fairness Policy | Not configurable | Can specify fairness (FIFO order) |
| Performance | Simpler but less flexible | Better for highly concurrent applications |
๐ป Example — Using ReentrantLock for Thread Safety
Let’s see how to use a concurrent lock to safely simulate email sending from multiple threads.
๐ Code Example
๐งพ Example Output
Each thread waits for the lock to be released before sending its email, ensuring thread safety even when multiple threads try to access the shared resource simultaneously.
๐ง How It Works — Step by Step
-
Main thread creates an
ExecutorServicewith 25 threads. -
Each thread submits a
SendEmailThreadtask. -
Every task calls
emailProcessor.sendEmail(). -
Inside
sendEmail(), theReentrantLockensures only one thread executes the email-sending block at a time. -
After sending, the lock is released in the
finallyblock, allowing another thread to proceed.
๐งฉ Why Use Locks Instead of synchronized
While synchronized is simpler for basic use cases, Lock provides:
-
More precise control over locking and unlocking.
-
Ability to back off after waiting (e.g., using
tryLock()). -
Better visibility and diagnostics for debugging concurrent issues.
๐งฑ Example with Timeout (Optional Enhancement)
Here’s how you can use tryLock() with a timeout:
This avoids blocking indefinitely if another thread holds the lock for too long.
๐งญ Key Takeaways
| Concept | Summary |
|---|---|
| Lock Interface | Provides explicit locking control |
| ReentrantLock | Most commonly used Lock implementation |
| Best Practice | Always unlock in a finally block |
| tryLock() | Enables timeout-based lock attempts |
| When to Use | High concurrency scenarios where synchronized is too restrictive |
No comments:
Post a Comment