ReentrantLock源码分析:如何实现可重入锁?
2023-11-14 08:19:35
ReentrantLock 的基本原理
ReentrantLock 的基本原理是使用 AQS(AbstractQueuedSynchronizer)来实现加锁和解锁。AQS 的内部就是一个 int 状态字段 state 和一个 FIFO 等待队列(双向链表),state 等于 0 表示没有线程持有锁,大于 0 表示有线程持有锁,state 的值等于持有锁的线程数。
当一个线程要获取锁时,它会首先尝试通过 CAS(Compare And Swap)将 state 的值从 0 改为 1,如果成功,则表示该线程获得了锁。如果失败,则表示已经有其他线程获得了锁,该线程会被加入到等待队列中。
当持有锁的线程释放锁时,它会将 state 的值减 1,如果 state 的值变为 0,则表示没有线程持有锁,此时等待队列中的线程会争抢着获取锁。
ReentrantLock 的可重入性
ReentrantLock 的可重入性是指同一个线程可以多次获取同一把锁。这是因为 ReentrantLock 在判断是否要将线程加入到等待队列时,会先检查该线程是否已经持有锁,如果已经持有锁,则不会将该线程加入到等待队列中。
ReentrantLock 的公平性和非公平性
ReentrantLock 提供了公平锁和非公平锁两种选择。公平锁是指线程获取锁的顺序与它们进入等待队列的顺序一致,非公平锁是指线程获取锁的顺序与它们进入等待队列的顺序无关。
在公平锁下,如果一个线程在等待队列中排在其他线程之后,那么它只能等到前面的线程都获取了锁之后才能获取锁。而在非公平锁下,一个线程在等待队列中的位置并不影响它获取锁的顺序,它有可能在前面的线程之前获取锁。
ReentrantLock 的使用示例
ReentrantLock 的使用非常简单,只需要在需要加锁的代码块前面使用 try-lock 代码块,并在 try 代码块中执行需要加锁的操作即可。例如:
ReentrantLock lock = new ReentrantLock();
try {
lock.lock();
// 需要加锁的操作
} finally {
lock.unlock();
}
总结
ReentrantLock 是 Java 并发库中一个非常重要的锁实现,它不仅支持可重入锁,还提供了公平锁和非公平锁两种选择。通过分析 ReentrantLock 的源码,我们可以深入理解它的实现原理和使用方法。