返回

ReentrantLock 源码解析——探秘加锁过程

见解分享

当我们使用带参数的构造器生成 ReentrantLock 时,由于传入的是 true,所以会生成一个公平锁的内部类对象。无论是公平锁还是非公平锁都继承了 ReentrantLock 中 Sync 这个静态内部类对象,而这个对象又继承了 AbstractQueuedSynchronizer(以下简称 AQS)。

AQS 是一个抽象的同步器,提供了同步的基本实现,它定义了一个同步状态 state,该状态可以是 0(未锁)或 1(已锁)。当线程试图获取锁时,它会调用 AQS 的 acquire 方法,如果 state 为 0,则将 state 设置为 1,表示锁已被获取;如果 state 为 1,则线程将被阻塞,直到 state 变为 0。

ReentrantLock 在 AQS 的基础上增加了锁的重入特性,即一个线程可以多次获取同一个锁,而不会发生死锁。ReentrantLock 的构造函数会创建一个 Sync 对象,并将该对象作为 ReentrantLock 的同步器。

当线程调用 ReentrantLock 的 lock 方法时,它会调用 Sync 的 acquire 方法来获取锁。如果当前线程已经持有该锁,则直接将 state 增加 1,表示锁的重入次数增加;如果当前线程没有持有该锁,则需要尝试获取锁。

Sync 的 acquire 方法首先会尝试使用 CAS 操作将 state 从 0 设置为 1,如果成功,则表示该线程已获取锁;如果失败,则表示其他线程正在持有该锁,当前线程将被阻塞,直到 state 变为 0。

当线程调用 ReentrantLock 的 unlock 方法时,它会调用 Sync 的 release 方法来释放锁。Sync 的 release 方法会将 state 减 1,如果 state 为 0,则表示锁已被释放,当前线程可以继续执行;如果 state 不为 0,则表示还有其他线程持有该锁,当前线程将继续阻塞,直到 state 变为 0。

ReentrantLock 的公平锁和非公平锁的区别在于,公平锁在获取锁时会按照线程进入等待队列的顺序来获取锁,而非公平锁则没有这个限制,任何线程都有可能获取锁。

ReentrantLock 的独占锁和共享锁的区别在于,独占锁不允许其他线程同时获取该锁,而共享锁允许其他线程同时获取该锁。

ReentrantLock 的同步队列是一个 FIFO(先进先出)队列,它存储了正在等待获取锁的线程。当一个线程调用 ReentrantLock 的 lock 方法时,如果该锁已经被其他线程获取,则当前线程将被添加到同步队列中,并阻塞等待。当该锁被释放时,同步队列中的第一个线程将被唤醒,并获取该锁。

ReentrantLock 的条件队列也是一个 FIFO 队列,它存储了正在等待某个条件的线程。当一个线程调用 ReentrantLock 的 wait 方法时,如果该条件不满足,则当前线程将被添加到条件队列中,并阻塞等待。当该条件满足时,条件队列中的第一个线程将被唤醒,并继续执行。

ReentrantLock 的节点是一个数据结构,它存储了线程、等待状态和前驱节点。当一个线程调用 ReentrantLock 的 lock 方法时,如果该锁已经被其他线程获取,则当前线程将创建一个节点,并将该节点添加到同步队列中。当该锁被释放时,同步队列中的第一个节点将被唤醒,并获取该锁。

ReentrantLock 的状态是一个整数值,它表示该锁的当前状态。ReentrantLock 的状态可以是 0(未锁)、1(已锁)、2(正在等待获取锁)或 3(正在等待某个条件)。

ReentrantLock 的线程是一个 Thread 对象,它表示正在持有该锁的线程。ReentrantLock 的线程可以是 null,表示该锁没有被任何线程持有。

ReentrantLock 的等待队列是一个 FIFO 队列,它存储了正在等待获取锁的线程。ReentrantLock 的等待队列可以使用数组或链表实现。

ReentrantLock 的唤醒线程是一个 Thread 对象,它表示正在唤醒其他线程的线程。ReentrantLock 的唤醒线程可以是 null,表示没有线程正在唤醒其他线程。