首先让我们先看下 ReentrantLock 的类结构如下图所示:
从图中我们可以看出 ReentrantLock 实现 Lock 接口,同时内部类 Sync 是 AQS 的子类;而 Sync 又有两个子类 NonfairSync 和 FairSync 分别对应非公平和公平锁两种策略。
public ReentrantLock() { sync = new NonfairSync(); } 复制代码
public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } 复制代码
ReentrantLock 默认采用非公平的策略,也可以在构造的时候指定是否公平的策略。
非公平锁是指在竞争获取锁的过程中,有可能后来者居上
static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { // CAS 设置 state 值为 1 if (compareAndSetState(0, 1)) // CAS 成功则说明获取到锁, 此时将当前线程设置为独占模式下锁对象的持有者 setExclusiveOwnerThread(Thread.currentThread()); else // CAS 失败 // 可能是同一线程再次获取锁 // 也可能是不同线程获取锁 acquire(1); } protected final boolean tryAcquire(int acquires) { // 调用父类 sync return nonfairTryAcquire(acquires); } } 复制代码
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // 此时说明已有线程释放了锁 // 有可能是同步队列里阻塞的线程被唤醒时尝试获取锁 if (compareAndSetState(0, acquires)) { // CAS 成功则说明获取到锁, 此时将当前线程设置为独占模式下锁对象的持有者 setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { // 说明同一线程再次获取锁 // state 加 1 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } 复制代码
获取锁的过程如下 :
非公平锁的释放调用的是父类 sync 的 tryRelease 方法
protected final boolean tryRelease(int releases) { // state 减一操作 int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) // 当前线程不是当前锁的持有者时抛出异常 throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { // 只有 state == 0 时 才是真正完成锁的释放 free = true; // 将锁的持有者清空 setExclusiveOwnerThread(null); } setState(c); return free; } 复制代码
从释放锁的实现可以看出,获取锁与释放锁的操作是对等的,譬如下方伪代码:
ReentrantLock lock = new ReentrantLock(); public void do () { lock.lock(); try { do(); // 退出递归 } finally { lock.unlock(); } } 复制代码
公平锁是指获取锁的顺序完全符合请求时间的顺序,也就是先到先得
接下来我们下公平锁与非公平锁在获取锁时有什么不同
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // 不同于非公平锁操作,公平锁多了个判断条件 hasQueuedPredecessors if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } 复制代码
public final boolean hasQueuedPredecessors() { // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; // h != t 说明同步队列已有等待的节点 // s = h.next == null 这个有点没明白; head 的后置为空应该就是 head == tail 吧 // s.thread != Thread.currentThread 是判断当前线程是不是同步队列的首个阻塞线程 如果是是允许获取到锁的 return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); } 复制代码
Queries whether any threads have been waiting to acquire longer than the current thread. 复制代码
hasQueuedPredecessors 方法主要实现的是查找是否有等待时间超过当前线程的其他线程, 公平锁也就是通过该方法保证获取锁的有序性。