Comparing ReentrantLock and Synchronized in Java
In Java, both ReentrantLock and the synchronized keyword are used to achieve thread synchronization and prevent race conditions. However, they differ in their approach, features, and behavior. This table highlights the key differences between ReentrantLock and Synchronized:
Sr. No. | Key | ReentrantLock | Synchronized |
---|---|---|---|
1 | Acquire Lock | ReentrantLock provides the lock() method to acquire a lock on the shared resource by a thread. | You need to use the synchronized keyword to acquire a lock. |
2 | Release Lock | To release a lock, programmers must explicitly call the unlock() method. | The lock is released implicitly when the synchronized block or method exits. |
3 | Ability to Interrupt Lock | The lockInterruptibly() method can be used to interrupt a thread waiting for a lock. | There is no direct way to interrupt a thread waiting for a lock when using the synchronized keyword. |
4 | Fairness | The constructor of ReentrantLock has a fairness parameter. If set to true, locks favor granting access to the longest-waiting thread. | The synchronized keyword does not guarantee any particular access order. |
5 | Lock Release Order | Locks acquired by a ReentrantLock can be released in any order. | Locks acquired using the synchronized keyword must be released in the reverse order of acquisition. |
6 | Performance | ReentrantLock may have slightly better performance in situations with high contention due to its ability to back off and retry. | The synchronized keyword may perform slightly better in situations with low contention. |
7 | Scalability | ReentrantLock can potentially provide better scalability in some cases due to its advanced features like fairness and lock polling. | The synchronized keyword can be less scalable in certain scenarios due to its lack of advanced features. |
8 | Flexibility | ReentrantLock provides more flexibility and advanced features, such as timed locks, interruptible locks, and fair/non-fair acquisition modes. | The synchronized keyword is more straightforward but less flexible. |
Examples:
1. Synchronized Example:
public class SynchronizedExample {
private static int counter = 0;
public static synchronized void increment() {
counter++;
}
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Counter: " + counter); // Output: Counter: 20000
}
}
2. ReentrantLock Example:
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private static int counter = 0;
private static ReentrantLock lock = new ReentrantLock();
public static void increment() {
lock.lock();
try {
counter++;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Counter: " + counter); // Output: Counter: 20000
}
}
In both examples, we have a shared counter
variable that is incremented by two threads concurrently. In the first example, we use the synchronized
keyword to ensure thread-safe access to the increment()
method. In the second example, we use a ReentrantLock to achieve the same thread safety.
The output of both examples is Counter: 20000
, which is the expected result after incrementing the counter 10,000 times by each thread.
While the synchronized
keyword provides a straightforward way to achieve thread synchronization, ReentrantLock offers more advanced features and flexibility, such as fairness, lock polling, and the ability to interrupt a thread waiting for a lock. However, the choice between the two depends on the specific requirements of your application and the level of control and flexibility you need.