Appearance
ReentrantLock
Since Java 5, the java.util.concurrent
package was introduced to provide advanced concurrency handling, offering numerous features that greatly simplify the writing of multithreaded programs.
Java provides the synchronized
keyword for locking, but this type of lock is heavyweight and requires threads to wait indefinitely when attempting to acquire it, without any additional retry mechanism.
The ReentrantLock
class from the java.util.concurrent.locks
package can be used as an alternative to synchronized
. Let's look at the traditional synchronized
code:
java
public class Counter {
private int count;
public void add(int n) {
synchronized(this) {
count += n;
}
}
}
If we replace it with ReentrantLock
, the code can be refactored as follows:
java
public class Counter {
private final Lock lock = new ReentrantLock();
private int count;
public void add(int n) {
lock.lock();
try {
count += n;
} finally {
lock.unlock();
}
}
}
Since synchronized
is a language-level feature in Java, we do not need to handle exceptions explicitly. However, ReentrantLock
is a lock implemented in Java code, so we must acquire the lock first and then release it properly in a finally
block.
As the name suggests, ReentrantLock
is a reentrant lock, meaning that a thread can acquire the same lock multiple times, just like with synchronized
.
Unlike synchronized
, ReentrantLock
allows an attempt to acquire the lock:
java
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try {
// Code to execute if the lock is acquired
} finally {
lock.unlock();
}
}
In the code above, when attempting to acquire the lock, the maximum wait time is 1 second. If the lock is not acquired within 1 second, tryLock()
returns false
, allowing the program to perform additional handling rather than waiting indefinitely.
Therefore, using ReentrantLock
is safer than using synchronized
directly, as a failed tryLock()
will not lead to a deadlock.
Summary
ReentrantLock
can be used as an alternative tosynchronized
for synchronization.- Acquiring a lock with
ReentrantLock
is safer. - The lock must be acquired before entering the
try {...}
block, and afinally
block should be used to ensure the lock is released. tryLock()
can be used to attempt to acquire the lock.