ReentrantLock-基于AQS实现独占锁

1,854 阅读2分钟

1 概述

ReentrantLock是基于AQS实现的一款独占锁,有公平锁和非公平锁两种模式。

默认是使用的非公平锁:

    public ReentrantLock() {
        sync = new NonfairSync();
    }

也可指定模式:

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
  • 1 ReentrantLock实现了Lock接口;
  • 2 ReentrantLock定义了内部类Sync继承AQS:abstract static class Sync extends AbstractQueuedSynchronizer{....}
  • 3 Sync是一个抽象类,有两个实现类NonfairSync/FairSync,分别用来实现非公平锁/公平锁

官方示例:

class X {
    private final ReentrantLock lock = new ReentrantLock();
    // ...
 
    public void m() {
      lock.lock();  // block until condition holds
      try {
        // ... method body
      } finally {
        lock.unlock()
      }
    }
  }

2 实现

本文仅从ReentrantLock的lock/unlock的实现,分析如何基于AQS实现一个独占锁。

根据AQS约定(可参考AQS源码分析及核心方法解析):

  • 1 lock:实现tryAcquire,并在lock时调用acquire
  • 2 unlock:实现tryRelease,并在unlock时调用release

2 lock()

ReentrantLock.lock()调用了Sync.lock(),而Sync.lock()是一个抽象方法,由子类实现。

所以NonfairSync/FairSync两个类中,必然使用了acquire方法去获取锁,并实现了tryAcquire方法。

2.1 NonfairSync

2.1.1 lock

  • 1 调用compareAndSetState将state值由0置换为1,成功的话,说明当前没有其他线程持有锁,不去排队,直接持有。通过setExclusiveOwnerThread将当前线程设置为独占锁持有者。
  • 2 否则通过acquire去排队。
        final void lock() {
            if (compareAndSetState(0, 1)) // 如果当前state==0,则说明没有其他线程持有锁,CAS成功。
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

2.1.2 tryAcquire

NonfairSync.tryAcquire直接调用的Sync.nonfairTryAcquire

nonfairTryAcquire是非公平的tryAcquire实现方式,不会通过AQS.hasQueuedPredecessors来判断是有线程在排队。

        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                // state == 0,说明没有其他线程持有锁。
                if (compareAndSetState(0, acquires)) {
                    // 将当前线程设置为`独占锁持有者`,tryAcqire成功。
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                /* 
                如果当前线程正是`独占锁持有者`,叠加state,实现`可重入`,tryAcqire成功。
                也就是说AQS的同步列表中,有多个当前线程的节点。
                */
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

2.2 FairSync

2.2.1 lock

没有做compareAndSetState尝试,直接将自己加入AQS的同步队列中。

        final void lock() {
            acquire(1);
        }

2.2.2 tryAcquire

        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {  // state == 0,说明没有其他线程持有锁。
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    /*
                    `!hasQueuedPredecessors()` 说明AQS的同步队列中,没有比自己更优先的线程在等待
                    */
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                /* 
                如果当前线程正是`独占锁持有者`,叠加state,实现`可重入`,tryAcqire成功。
                也就是说AQS的同步列表中,有多个当前线程的节点。
                */
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

FairSync.tryAcquireNonFairSync.tryAcquire多了一个!hasQueuedPredecessors()的判断,其他流程都是一样的。

3 unlock()

unlock操作,NonFairSync/FairSync中没有区分,直接在Sync中实现。

Sync中的unlock调用了AQS.release,并实现了tryRelease

public void unlock() {
        sync.release(1);
    }

3.1 tryRelease

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            
            // 当前线程不是`独占锁持有者`,抛出异常。
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) { // c == 0 说明锁已经完全释放。
                free = true;
                // 将当前`独占锁持有者`置空。
                setExclusiveOwnerThread(null);
            }
            // 更新state值
            setState(c);
            return free;
        }

4 总结

NonFairSync/FairSync基本流程是一样的,不同的是:

  • 1 NonFairSync在lock时,会先尝试compareAndSetState(0, 1)抢占锁,失败的话再进行acquire(1)FairSync直接进行acquire(1)排队。
  • 2 FairSynctryAcquire时,在判断compareAndSetState(0, acquires)的同时,多进行了一个hasQueuedPredecessors()的判断,用于判断同步队列中是否有比自己优先的线程。