ReentrantLock源码(jdk1.8)

ReentrantLock比较常用的一个锁,基于AQS实现,支持可重入性,公平锁和非公平锁两种模式。
ReentrantLock的可重入性是通过对同步状态值state进行累加实现;ReentrantLock有三个内部类,分别是Sync,NonfairSync,FairSync他们的继承关系如下图所示,ReentrantLock持有一个Sync类型的引用,根据多态的思想,在公平锁和非公平锁模式下,分别将子类FairSync和NonfairSync对象引用赋值给他,这两个子类同步器中实现了具体的获取锁策略,来实现公平锁和非公平锁。

建议看完AQS关键源码再看来这部分,就会非常简单,当然不看也影响不大。
在这里插入图片描述

  1. 基本字段
private static final long serialVersionUID = 7373984872572414699L; //用于序列化,以后略去该字段

private final Sync sync; //NonfairSync和FairSync的基类引用,通过多态来分别实现公平锁和非公平锁
  1. lock方法
    public void lock() {
        sync.lock();
    }

由于这里用到了多态,所以我们分别分析公平锁和非公平的lock方法。

FairSync的lock方法:

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

直接调用了AQS的acquire方法,acquire方法是AQS很重要的一个函数,这里不做分析,读者只需要知道这个acquire方法里会首先调用一个tryAcquire方法,而这个方法是AQS留给我们来重写的,FairSync的重写的tryAcquire方法:

        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            /**
             * C == 0是首次获取锁
             * !hasQueuedPredecessors()保证竞争锁的线程一定是同步队列的头结点
             * 由于if短路,其他结点会直接返回,所以是公平锁,按照FIFS的顺序,只允许队头也就是最早来的节点竞争锁
             */
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) { //可重入实现,由于这里已经持有锁了,所以不需要在做同步了
                int nextc = c + acquires; //对同步器状态值,不断增加来实现可重入
                if (nextc < 0) //int溢出
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false; //获取锁失败
        }
    }

接下来分析NonfairSync的lock方法:

        final void lock() {
            if (compareAndSetState(0, 1))//进行一次快速抢占锁
                setExclusiveOwnerThread(Thread.currentThread());
            else //抢占失败的线程,调用AQS的acquire方法,继续进行竞争锁
                acquire(1);
        }

同理,NonfairSync也重写了AQS的tryAcquire方法,如下:

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

这个nonfairTryAcquire是Sync类提供的一个内部方法,因为这个nonfairTryAcquire方法不仅在这里被使用,还在tryLock方法中使用,所以作者将重复的代码封装成了一个函数。nonfairTryAcquire函数代码如下:

       final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                /**
                 * 这里通过CAS保证只有一个线程能获取锁成功,但是会让所有线程进行竞争
                 * 与先后顺序无关,是非公平锁
                 */
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) { //可重入支持
                int nextc = c + acquires;
                if (nextc < 0) // int溢出,一般来说不会重入这么多次
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

可以看到nonfairTryAcquire里并没有hasQueuedPredecessors这个限制,所以是非公平的。

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

对于公平锁和非公平所来说,释放锁的逻辑没有区别,所以在父类Sync中重写了AQS的tryRelease方法,这里是先调用了AQS的release方法(因为AQS是Sync的父类),然后release方法中首先调用了tryRelease方法,同样这是提供给用户来重写的方法,如下:

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread()) //如果非持有线程来释放锁,直接抛出异常
                throw new IllegalMonitorStateException();
            boolean free = false;
            /**
             * 由于可重入,所有一次释放可能c还不等于0,直到c=0才会真正释放锁
             * 这点来保证n次重复获取锁,必须也要进行n次释放
             */
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
  1. tryLock方法
    之前提到过tryLock方法,tryLock方法是进行一次快速获取锁尝试,所以肯定是非公平的,不论是否成功都立刻返回,代码如下:
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

此外还有一些可响应中断的获取锁方法,超时返回的获取锁,是否公平,是否被当前线程持有锁等函数,比较简单,就不在此赘述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值