什么是可重入锁 ReentrantLock?
在并发编程中,线程安全是一个重要的概念,尤其是在多线程环境下,资源共享往往导致竞争条件。为了解决这个问题,Java 提供了多种同步机制,其中之一是可重入锁(ReentrantLock)。可重入锁允许同一个线程多次获取同一把锁,而不会导致死锁。

可重入锁的特点
-
重入性:同一个线程可以多次获取同一把锁,而不会被阻塞。例如,如果一个线程已经持有一个锁,再次尝试获取这个锁时,它可以直接获取成功,而不会被挂起。
-
独占性:在锁被一个线程持有的情况下,其他线程不能获取这个锁,必须等待直到锁被释放。
-
可公平性:ReentrantLock 可以选择公平性策略,确保线程获取锁的顺序是按照请求锁的顺序。如果设置为非公平锁,线程可以在没有任何顺序的情况下获取锁。
-
灵活性:ReentrantLock 提供了更高的灵活性和功能,比如可以中断锁的请求、增加时间限制等。
使用场景
可重入锁适用于需要递归调用的场景,例如在一个方法中调用另一方法,这两个方法都需要持有相同的锁来保护共享资源。使用 ReentrantLock 还可以通过其提供的方法来更好地控制并发行为。
Java 示例代码
以下是一个使用 ReentrantLock 的示例:
java
import java.util.concurrent.locks.ReentrantLock;
class SharedResource {
private final ReentrantLock lock = new ReentrantLock();
private int counter = 0;
// 增加计数器并打印当前值
public void increment() {
lock.lock(); // 获取锁
try {
counter++;
System.out.println("Counter: " + counter);
// 由于是可重入锁,这里可以再次尝试获取锁
this.incrementInner();
} finally {
lock.unlock(); // 保证释放锁
}
}
private void incrementInner() {
lock.lock();
try {
counter++;
System.out.println("Counter (inner): " + counter);
} finally {
lock.unlock();
}
}
}
public class ReentrantLockExample {
public static void main(String[] args) {
SharedResource sharedResource = new SharedResource();
// 创建多个线程来测试可重入锁
Thread thread1 = new Thread(sharedResource::increment);
Thread thread2 = new Thread(sharedResource::increment);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
代码解析
- 共享资源类 :定义了一个
SharedResource类,其中包含一个ReentrantLock实例和一个整数计数器。 - increment 方法 :这个方法获取锁,增加计数器的值,然后调用另一个内部方法
incrementInner,这展示了ReentrantLock的重入特性,因为同一个线程可以再次获取已经持有的锁。 - incrementInner 方法:同样获取锁,增加计数器,并打印值。
- 主方法 :创建了两个线程,它们同时调用
increment方法,从而测试了线程安全和可重入性。
最后小结下哈
ReentrantLock 是一种强大的工具,用于管理并发访问共享资源。通过允许可重入操作,它在保护数据一致性和提高系统性能方面发挥了重要作用。然而,使用可重入锁时,开发者需谨慎,确保在 try-finally 结构中释放锁,以避免潜在的死锁或资源泄漏问题。