【JUC】ReentrantLock实现和原理

492 阅读3分钟

一、概述

ReentrantLock是基于AQS实现的一种独占可重入锁,利用自旋和CAS实现的轻量锁,提供公平和非公平锁

二、常用方法

lock()

获取锁,如果不能获取则阻塞当前线程,直到获取锁

lockInterruptibly()

可中断的锁获取,与lock功能类似,如果线程中断则抛出InterruptedException

tryLock()

尝试获取锁,无论是否获取成功,立即返回

tryLock(long timeout, TimeUnit unit)

尝试获取锁,在超时时间内获取到锁则返回true,如果不能获取锁,则返回false;

unLock()

释放锁

三、源码

1、Sync同步器

提供了非公平锁的获取和

tryAcquire在各自子类实现

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

    @ReservedStackAccess
    final boolean nonfairTryAcquire(int acquires) {
        // acquires代表需要获取锁的数量
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            // 非公平锁,可以直接竞争获取(state是AQS持有的一个计数器,表示锁获取的数量)
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            //	重入等于单线程,线程安全
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }

    // 释放锁
    @ReservedStackAccess
    protected final boolean tryRelease(int releases) {
        // releases释放锁的数量
        int c = getState() - releases;
        // 未持有锁调用线程调用直接抛出IllegalMonitorStateException异常
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;
        if (c == 0) {
            // 锁全部释放则将独占线程设置为null
            free = true;
            setExclusiveOwnerThread(null);
        }
        setState(c);
        return free;
    }

    protected final boolean isHeldExclusively() {
        // While we must in general read state before owner,
        // we don't need to do so to check if current thread is owner
        return getExclusiveOwnerThread() == Thread.currentThread();
    }

    final ConditionObject newCondition() {
        return new ConditionObject();
    }

    // Methods relayed from outer class

    final Thread getOwner() {
        return getState() == 0 ? null : getExclusiveOwnerThread();
    }

    final int getHoldCount() {
        return isHeldExclusively() ? getState() : 0;
    }

    final boolean isLocked() {
        return getState() != 0;
    }

    /**
     * Reconstitutes the instance from a stream (that is, deserializes it).
     */
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0); // reset to unlocked state
    }
}

2、非公平同步器

代码很简单,通过调用父类的nonfairTryAcquire方法尝试获取锁

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

3、公平同步器

除非是重入或者没有线程在队列等待,否则返回false

static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;
 
    @ReservedStackAccess
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            // 没有线程持有锁,队列没有线程等待,CAS设置成功则获取锁
            if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            // 重入的场景,相当于单线程进入可直接修改state
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
}

4、构造函数

默认使用非公平锁

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

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

5、lock、lockInterruptibly

两者实现相似,lockInterruptibly如果线程中断则会抛出InterruptedException异常

public void lock() {
    sync.acquire(1);
}
public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}

调用的是AQS中方法,下面可以看到AQS将会调用到子类实现的tryAcquire()来实现锁的获取

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

public final void acquireInterruptibly(int arg)
    throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg);
}

6、tryLock

可以看到无论是公平还是非公平都是调用Sync提供非公平获取,这是一个需要立即返回结果的对锁的尝试获取

public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}

7、unlock

调用AQS中的释放

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

首先会调用子类实现的tryRelease,如果释放成功且有线程在等待则唤醒队列中等待线程

public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}