JUC并发编程基石AQS源码之结构篇-ReentrantLock

上篇文章JUC并发编程基石AQS源码之结构篇我们整体了解了JUC下加锁类的代码结构,这篇我们来看下ReentrantLock的代码结构,之后讲解AQS源码也主要以这个类为主。

实现Lock接口

首先是实现了Lock接口,实现了加锁方法lock(),但是这里没有直接调用AQS的acquire方法,往下看

public class ReentrantLock implements Lock, java.io.Serializable {
  
  public void lock() {
        sync.lock();
    }
  

定义内部类

先看一下内部类的继承关系,会发现比上一篇多了一层继承关系,我们来慢慢分析

在这里插入图片描述

定义了一个抽象内部类Sync继承了AQS,定义了一个抽象方法lock,但是会发现没有实现tryAcquire()方法,再往下看

public class ReentrantLock implements Lock, java.io.Serializable {

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

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                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;
        }

又一个内部类NonfairSync实现了Sync,实现了Sync类的lock()方法,并且实现了tryAcquire方法。lock方法里调用了AQS的acquire()方法。

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() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

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

到这我们就能梳理出大致的调用流程了,其中绿色部分代表需要自己实现

在这里插入图片描述

为什么多了一层结构?因为ReentrantLock有两种锁类型,公平锁和非公平锁

公平锁:不能插队,如果当前有线程在等待锁,则直接进入排队队列,等待在它之前排队的所有线程执行完后再去获取锁。

非公平锁:不管当前是否有其他线程在排队等待锁,先尝试获取一次锁,如果获取到则执行代码逻辑,否则进入排队队列,等待在它之前排队的所有线程执行完后再去获取锁。

而实现不同锁类型在代码上的体现就是对AQS的tryAcquire()方法的不同实现,有几种锁类型就有几个内部类。

在这里插入图片描述

再看上面这张图就会明白,NonfairSync代表了非公平锁的实现。FairSync代表了公平锁的实现。

加锁类型不同会有不同的tryAcquire()方法实现,其他的解锁等操作的逻辑是一致的,所以根据代码的重用性思想,就抽象出了Sync类。所以我们看Sync类只把加锁的方法抽象了,其他的都是具体的实现。

再看一下公平锁FairSync的代码,也只是实现了加锁的方法。

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

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

    /**
     * Fair version of tryAcquire.  Don't grant access unless
     * recursive call or no waiters or is first.
     */
    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;
    }
}

ReentrantLock默认的锁方式为非公平锁,构造方法中新建了NonfairSync的实例。所以在抽象类Sync默认给出了非公平锁的实现方法nonfairTryAcquire()。

//ReentrantLock构造方法
public ReentrantLock() {
    sync = new NonfairSync();
}

到此ReentrantLock类的结构我们大体都了解了,这样我们再去看源码才会有的放矢,知道为什么会跳到这个类的这个方法来执行了,这也是看懂AQS源码的第一个关键。

如有不实,还望指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值