ReentrantLock源码详解

54 阅读2分钟

ReentrantLock源码详解

1. 首先先看ReentrantLock的构造器

public class ReentrantLock {

    public ReentrantLock() {
        // 默认的构造器就是非公平锁
        sync = new NonfairSync();
    }

    public ReentrantLock(boolean fair) {
        // 可以通过入参来构造是公平的还是非公平的  
        sync = fair ? new FairSync() : new NonfairSync();
    }

    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        try{
            lock.lock();
            // do something;
        } finally{
            lock.release();
        }
    }       

}

2. NofairSync类

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;

    final void lock() {
        // 第一次尝试以非公平的方式获取锁
        if (compareAndSetState(0, 1))
            // 线程通过CAS来获取锁,如果当前锁的状态是0(代表此时锁还没有被其他线程占有),那么该锁将被该线程独占
            setExclusiveOwnerThread(Thread.currentThread());
        else
            // 如果通过CAS来获取锁,如果当前锁的状态是1,则调用父类(AbstractQueuedSynchronizer)的acquire方法。
            // 而父类的acquire方法则会调用由子类实现的tryAcquire方法。
            acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = -5179523762034025860L;

    abstract void lock();

    final boolean nonfairTryAcquire(int acquires) {
        // 获取当前线程
        final Thread current = Thread.currentThread();
        // 获取当前同步器的状态,如果c为0表示未上锁
        int c = getState();
        if (c == 0) {
            // 第二次尝试以非公平的方式获取锁
            // 通过CAS的原子操作将同步器的状态设置为acquires.
            if (compareAndSetState(0, acquires)) {
                // 如果设置成功,那么当前线程将独占该锁。
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        // 重入锁实现的原理: 如果是当前线程独占了锁
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            // 最大可重入的次数为Integer.MAX_VALUE,如果再加1则会溢出
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            // 设置重入锁的次数
            setState(nextc);
            return true;
        }
        return false;
    }

    /**
                 * 释放锁
                 */
    protected final boolean tryRelease(int releases) {
        // 由于reentrantLock是可重入的,所以只有在同步器的状态为0时才能释放锁
        int c = getState() - releases;
        // 只有持有锁的线程才能进行release,不然会报错哦
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;
        if (c == 0) {
            free = true;
            // 将占用锁的线程设置为null
            setExclusiveOwnerThread(null);
        }
        setState(c);
        return free;
    }


}

3. 非公平锁竞争锁的过程

  • 插队成功的情况 image
  • 插队失败的情况 image

4. FairSync类


static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

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

    /**
      * 公平锁模式下获取锁
      */
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            // 公平锁与非公平锁只相差这一行代码
            // 线程获取锁时会查看该线程是否与首个节点的线程是否相同,如果相同则可以获取锁,不然的只能老老实实排队
            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;
    }
}

5. 公平锁竞争锁的过程

image