Java
Completed
-
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
83: ReentrantLock and Explicit Locking
If you've been using the synchronized keyword for a while, you've probably fallen into the trap of thinking: "ReentrantLock is just a more verbose way of doing the same thing; I'll just stick with synchronized because it's cleaner."
I used to think the same thing. It feels like adding boilerplate for no reason. But the problem with synchronized is that it's an "all or nothing" deal. Once a thread enters a synchronized block and hits a deadlock or a very slow process, that thread is stuck. It will wait forever. There is no "timeout," no "try this and move on," and no way to check if the lock is available without actually blocking the thread.
The Myth: Synchronized is Always the Best Default
Let's look at a classic deadlock scenario: transferring money between two accounts. If Thread A locks Account 1 and tries to lock Account 2, while Thread B locks Account 2 and tries to lock Account 1, your application just... stops. With synchronized, you're dead in the water. You can't tell the thread to "give up" after five seconds.
// This is the 'synchronized' trap public void transfer(Account from, Account to, double amount) { synchronized(from) { synchronized(to) { // If two threads do this in reverse order, they deadlock forever. from.withdraw(amount); to.deposit(amount); } } }In a production system, a deadlock like this is a nightmare because it doesn't throw an exception; the system just stops responding. This is where explicit locking becomes a lifesaver.
Taking Control with Explicit Locks
ReentrantLockis a class in thejava.util.concurrent.lockspackage. Unlikesynchronized, which is a language keyword,ReentrantLockis an actual object. This means you have a handle on the lock itself, allowing you to call methods on it to query its state or attempt to acquire it under specific conditions.The "Reentrant" part of the name just means that if a thread already holds the lock, it can acquire it again without locking itself out. It keeps a hold count, which is exactly how
synchronizedworks under the hood, so you don't lose that behavior.Avoiding the Forever-Wait with tryLock()
This is the "killer feature" of explicit locking. With
tryLock(), you can attempt to acquire the lock and, if it's held by another thread, immediately returnfalseinstead of blocking. You can even specify a timeout.private final ReentrantLock lock = new ReentrantLock(); public void performTask() { if (lock.tryLock()) { try { // We got the lock! Do the work. } finally { lock.unlock(); } } else { // We didn't get the lock. Instead of freezing, // we can log it, try again later, or alert the user. System.out.println("System busy, try again in a moment."); } }Imagine applying this to our bank transfer. Instead of deadlocking, the thread could try to lock both accounts; if it fails to get the second lock within 100 milliseconds, it releases the first lock and tries the whole operation again. The deadlock is broken because the threads are willing to "back off."
The Non-Negotiable Finally Block
Here is the most important piece of advice I can give you regarding
ReentrantLock: Always, always put your unlock() call in a finally block.With
synchronized, the JVM automatically releases the lock when the block ends, even if an exception is thrown. WithReentrantLock, the JVM doesn't manage the release. If your code throws aRuntimeExceptionbefore it hitsunlock(), that lock stays held forever. You've just created a manual deadlock that will require a full application restart to fix. I've seen this happen in production environments more times than I care to admit.
📋 Practical Task
Building a Deadlock-Resistant Bank Transfer System
In this exercise, you will implement a SafeBankTransfer class that prevents deadlocks using ReentrantLock. You will move away from synchronized and implement a "try-and-back-off" strategy.
Requirements:
- Create an
Accountclass with abalanceand aReentrantLockinstance. - Implement a
transfer(Account from, Account to, double amount)method. - Inside the transfer method, use
tryLock()` with a timeout (e.g., 50 milliseconds) to attempt to acquire locks for both accounts. - If both locks are acquired, perform the transfer and then unlock both in a
finallyblock. - If either lock cannot be acquired within the timeout, release any locks already held and return
false(indicating the transfer failed due to contention). - Test your implementation by creating two threads that attempt to transfer money between the same two accounts in opposite directions simultaneously. Verify that the program completes without freezing.
There are no comments for now.