深入理解ReentrantLock
在Java并发编程中,锁(Lock)是控制多个线程对共享资源访问的重要工具。虽然Synchronized
关键字是实现锁的常用方式,但它在功能上比较有限。ReentrantLock
是java.util.concurrent.locks
包中提供的一个更加灵活和强大的锁实现,它是一个可重入的互斥锁,它允许线程在获取锁之后再次获取该锁而不被阻塞。简单来说,如果一个线程已经持有了一个锁,再次请求获取该锁时,它可以成功获取而不会被阻塞。
ReentrantLock的基本用法
使用ReentrantLock
的基本步骤包括创建锁实例、加锁和解锁。以下是一个简单的例子:
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
public void performTask() {
lock.lock();
try {
// 关键代码段
System.out.println("Lock is held by: " + Thread.currentThread().getName());
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockExample example = new ReentrantLockExample();
Runnable task = () -> example.performTask();
Thread t1 = new Thread(task, "Thread-1");
Thread t2 = new Thread(task, "Thread-2");
t1.start();
t2.start();
}
}
在这个例子中,我们创建了一个ReentrantLock
实例,并在performTask
方法中使用lock.lock()
来获取锁,lock.unlock()
来释放锁。在try
块中执行关键代码以确保在任何情况下都会释放锁。
ReentrantLock的高级功能
可重入性
正如前面提到的,ReentrantLock
是可重入的。这意味着同一个线程可以多次获取同一个锁而不会陷入死锁。以下示例展示了这一特性:
public void reentrantLockExample() {
lock.lock();
try {
System.out.println("First lock acquired.");
lock.lock();
try {
System.out.println("Second lock acquired.");
} finally {
lock.unlock();
}
} finally {
lock.unlock();
}
}
公平锁与非公平锁
ReentrantLock
可以被配置为公平锁或非公平锁。公平锁意味着线程将以请求锁的顺序(FIFO)获得锁,而非公平锁则可能让某些线程“插队”。默认情况下,ReentrantLock
是非公平的。要创建公平锁,可以使用以下代码:
ReentrantLock fairLock = new ReentrantLock(true);
可中断锁获取
ReentrantLock
提供了一种机制,可以让线程在尝试获取锁时被中断。使用lock.lockInterruptibly()
方法,可以在获取锁的过程中响应中断:
public void performInterruptibleTask() {
try {
lock.lockInterruptibly();
try {
// 关键代码段
} finally {
lock.unlock();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// 处理中断
}
}
超时锁获取
ReentrantLock
还允许在获取锁时指定超时时间。如果在指定时间内无法获取锁,线程将会放弃获取锁的尝试:
public void performTimedTask() {
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
try {
// 关键代码段
} finally {
lock.unlock();
}
} else {
System.out.println("Could not acquire lock within 5 seconds");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// 处理中断
}
}
ReentrantLock与Synchronized的对比
灵活性
ReentrantLock
比Synchronized
更加灵活,提供了可中断的锁获取、超时锁获取和公平锁等特性。而Synchronized
则相对简单,只能用于基本的互斥锁定。
性能
在高竞争环境下,ReentrantLock
可能表现得比Synchronized
更好,因为它内部使用了一些优化策略,比如自旋锁。
可见性
ReentrantLock
提供了isHeldByCurrentThread()
等方法,可以方便地检测锁的状态,而Synchronized
则没有这种直接的方法。
参考链接
- Java 官方并发教程