JUC-ReentrantLock实现原理

什么是ReentrantLock ?

ReentrantLock 其实就是基于 AQS 实现的一个可重入锁,支持公平和非公平两种方式。

内部实现依靠一个 state 变量和两个等待队列:同步队列和等待队列。

利用 CAS 修改 state 来争抢锁。

争抢不到则入同步队列等待,同步队列是一个双向链表。

条件 condition 不满足时候则入等待队列等待,是个单向链表。

是否是公平锁的区别在于:线程获取锁时是加入到同步队列尾部还是直接利用 CAS 争抢锁。

参考图片:

image-20250213102228341

扩展

CAS操作

CAS 是一种硬件级别的原子操作,它比较内存中的某个值是否为预期值,如果是,则更新为新值,否则不做修改。

工作原理

  • 比较(Compare):CAS 会检查内存中的某个值是否与预期值相等。
  • 交换(Swap):如果相等,则将内存中的值更新为新值。
  • 失败重试:如果不相等,说明有其他线程已经修改了该值,CAS 操作失败,一般会利用重试,直到成功。

自旋锁

自旋锁(Spinlock) 是一种轻量级锁机制。线程在获取锁失败时不会立即进入阻塞状态,而是会在循环中反复尝试获取锁,直到成功。

这种方式避免了线程的上下文切换开销,所以称之为轻量级锁,适用于锁等待时间较短的场景

以下就是一个简单自旋锁的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class SpinLock {
private final AtomicBoolean lock = new AtomicBoolean(false);

public void lock() {
while (!lock.compareAndSet(false, true)) {
// 自旋等待
}
}

public void unlock() {
lock.set(false);
}

}

它的优点能避免线程上下文切换的开销,缺点主要有两点:

  • 锁饥饿问题:高并发场景,可能存在某个线程一直 CAS 失败,争抢不到锁。
  • 性能问题:多核处理器如果对同一变量高并发进行 CAS 操作,会导致总线风暴问题。