ReentrantLock 原理

ReentrantReadWriteLock 是通过加锁来保证线程安全的,它是 Java 源码中内置的加锁的类

ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
try {
    lock.writeLock().lock();
} finally {
    lock.writeLock().unlock();
}

那么它内部是通过什么方式来实现加锁的呢,通过以下源码中的注释便可清楚。

public ReentrantReadWriteLock() {
    this(false); // 默认是 false
}
public ReentrantReadWriteLock(boolean fair) {
    // 默认是不公平锁
    sync = fair ? new FairSync() : new NonfairSync();
    readerLock = new ReadLock(this);
    writerLock = new WriteLock(this);
}

先来看 WriteLock 的

// WriteLock
public void lock() {
    sync.acquire(1);
}
// Sync继承自 AbstractQueuedSynchronizer, acquire 方法是在 AbstractQueuedSynchronizer 里实现的
public final void acquire(int arg) {
    // 主要控制同步的逻辑在 tryAcquire
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt(); // 如果没有获取到锁,当前线程中断
}
// Sync 类中 tryAcquire 方法的实现
protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState(); // 持有该锁的数量
    int w = exclusiveCount(c);
    if (c != 0) {
        // 已经有持有该锁的
        if (w == 0 || current != getExclusiveOwnerThread())
            return false; // 持有锁的线程不是当前线程
        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        // 同一线程,如果是嵌套的,这里就是可重入锁的原理所在
        setState(c + acquires);
        return true;
    }
    // 还没有持有该锁的,如果写数量失败了,就返回 false
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false;
    // 设置持有锁的线程是当前线程
    setExclusiveOwnerThread(current);
    return true;
}

到这里加锁主要逻辑就结束了,那么解锁的呢?接着往下看,解锁跟加锁的过程比较类似

// WriteLock
public void unlock() {
    sync.release(1);
}
// Sync继承自 AbstractQueuedSynchronizer, acquire 方法是在 AbstractQueuedSynchronizer 里实现的
public final boolean release(int arg) {
    // 解锁的主要逻辑在 tryRelease
    if (tryRelease(arg)) {
        // ...
        return true;
    }
    return false;
}
// Sync 类的 tryRelease 实现
protected final boolean tryRelease(int releases) {
    // ...
    int nextc = getState() - releases; // 剩余的锁的数量
    boolean free = exclusiveCount(nextc) == 0; // 是否已经没有锁
    if (free)
        setExclusiveOwnerThread(null); // 如果已经没有锁,则持有线程置为 null
    setState(nextc); // 设置剩余锁的数量
    return free; // 返回是否已经不再持有锁
}

总结:ReentrantLock 就是通过设置当前持有锁的线程和持有锁的数量,加锁时候通过判断这些来决定是否能获取锁,如果暂时不能获取锁,则线程中断。解锁过程是修改相应的持有锁线程和持有锁数量。

猜你喜欢

转载自blog.csdn.net/hexiaosa91/article/details/81915652