Java中的可重入锁(ReentrantLock)技术详解
在Java并发编程中,锁是保证数据在多线程环境下一致性和安全性的重要机制。Java标准库提供了多种锁的实现,其中ReentrantLock
是可重入锁的一个典型实现,它属于java.util.concurrent.locks
包。相比于内置的synchronized
关键字,ReentrantLock
提供了更灵活和强大的功能。
1. 可重入锁的概念
可重入锁(ReentrantLock)允许同一线程多次获取同一把锁,而不会造成死锁。这种特性使得锁在同一线程内可以被递归使用,从而避免了在递归调用时可能出现的死锁问题。
2. ReentrantLock的基本使用
使用ReentrantLock
的基本步骤如下:
- 创建一个
ReentrantLock
对象。 - 在需要加锁的代码块前调用
lock()
方法获取锁。 - 在需要释放锁的代码块后调用
unlock()
方法释放锁。
示例代码:
java复制代码
import java.util.concurrent.locks.ReentrantLock; | |
public class ReentrantLockExample { | |
private final ReentrantLock lock = new ReentrantLock(); | |
public void someMethod() { | |
lock.lock(); // 获取锁 | |
try { | |
// 临界区,同一时间只有一个线程能执行这里的代码 | |
// ... | |
} finally { | |
lock.unlock(); // 释放锁 | |
} | |
} | |
// 递归调用示例 | |
public void recursiveMethod() { | |
lock.lock(); | |
try { | |
// ... | |
recursiveMethod(); // 递归调用自身,仍然可以获取锁 | |
// ... | |
} finally { | |
lock.unlock(); | |
} | |
} | |
} |
3. ReentrantLock的特性
- 可重入性:同一个线程可以多次获取同一把锁,而不会被阻塞。
- 公平锁与非公平锁:
ReentrantLock
可以构造为公平锁或非公平锁。公平锁会按照线程请求锁的顺序来分配锁,而非公平锁则可能允许插队,即新请求的线程可能会立即获取锁,而等待时间较长的线程可能会继续等待。默认情况下,ReentrantLock
是非公平锁。 - 中断响应:与
synchronized
不同,ReentrantLock
支持对等待锁的线程进行中断。 - 尝试锁:
ReentrantLock
提供了tryLock()
方法,该方法会尝试获取锁,如果锁当前可用则获取锁并立即返回true
,否则立即返回false
。 - 定时锁:
ReentrantLock
还提供了tryLock(long timeout, TimeUnit unit)
方法,该方法会尝试获取锁,但如果在给定的等待时间内仍然没有获取到锁,则返回false
。
4. ReentrantLock与synchronized的比较
synchronized
是Java内置的关键字,使用方便但功能有限;而ReentrantLock
是Java标准库中的一个类,提供了更多的功能。ReentrantLock
支持公平锁和非公平锁,而synchronized
只有非公平锁。ReentrantLock
支持对等待锁的线程进行中断,而synchronized
不支持。ReentrantLock
提供了更灵活的锁控制,如尝试锁和定时锁,而synchronized
不支持这些功能。
5. 总结
ReentrantLock
作为Java中的一个可重入锁实现,提供了比synchronized
更强大和灵活的功能。在需要更精细控制锁的行为时,使用ReentrantLock
是一个很好的选择。然而,由于其使用相对复杂,需要确保在finally
块中释放锁,以避免潜在的死锁问题。