一、ReentrantLock 概述
1.1 ReentrantLock 简介
故名思义,ReentrantLock
意为可重入锁,那么什么是可重入锁呢?可重入意为一个持有锁的线程可以对资源重复加锁而不会阻塞。比如下面这样:
public synchronized void f1() {
f2();
}
private synchronized void f2() {
}
ReentrantLock
除了支持可重入以外,还支持定义公平与非公平策略,默认情况下采用非公平策略。公平是指等待时间最长的线程会优先获取锁,也就是获取锁是顺序的,可以理解为先到先得。
公平锁保证了锁的获取按照 FIFO(先进先出)原则,但是需要大量的线程切换。非公平锁虽然减少了线程之间的切换增大了其吞吐量,但是可能会造成线程“饥饿”。
1.2 使用方式
public void f1() {
ReentrantLock lock = new ReentrantLock();
try {
lock.lock();
// ...
} finally {
lock.unlock();
}
}
与 synchronized
不同,使用 ReentrantLock
必须显示的加锁与释放锁。
1.3 与 synchronized 对比
相同点:
- 可重入,同一线程可以多次获得同一个锁
- 都保证了可见性和互斥性
不同点:
ReentrantLock
可响应中断、可轮回,为处理锁的不可用性提供了更高的灵活性,synchronized
不可以响应中断ReentrantLock
是 API 级别的,synchronized
是 JVM 级别(JVM 内置属性)的,因此内置锁可以与特定的栈帧关联起来ReentrantLock
可以实现公平锁,切可以实现带有时间限制的操作ReentrantLock
通过Condition
可以绑定多个条件
二、源码分析
了解了 ReentrantLock
的基本概念后,接下来就一起来看源码吧。其实 ReentrantLock
内的源码并不多,原因在于很多源码都在 AbstractQueuedSynchronizer
中,因此想要了解 ReentrantLock
源码的小伙伴需要先行了解下 AQS。
后面会给大家推荐几篇关于 AQS 源码介绍的文章,有兴趣的可以自行了解,或者到我的 GitHub 去查下相应的源码记录。点我前往 GitHub
2.1 构造函数
默认构造函数
public ReentrantLock() {
sync = new NonfairSync();
}
有参构造函数
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync()