ReentrantLock源码剖析一(概述)

一、简介

众所周知,Java并发组件中的一个重要框架就是AQS,简称同步器。全称AbstractQueuedSynchronizer,它是基于模板方法模式实现的。也就是说大体算法框架已经写好了,具体的一些细节需要用户去实现。AQS中有5个方法是用户根据需要实现的(排它锁与否):

protected boolean tryRelease(int arg) {
        throw new UnsupportedOperationException();
}
protected boolean tryReleaseShared(int arg) {
        throw new UnsupportedOperationException();
}
protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
}
protected int tryAcquireShared(int arg) {
        throw new UnsupportedOperationException();
}
protected boolean isHeldExclusively() {
        throw new UnsupportedOperationException();
}

二、ReentrantLock的骨架

ReentrantLock是排它锁,需要实现上面的两个排它方式的方法。看一下ReentrantLock的内部构造:
ReentrantLock锁依赖于Sync:

public class ReentrantLock implements Lock {
        ...
        private final Sync sync;
        ...
}

并在内部实现了Sync:

abstract static class Sync extends AbstractQueuedSynchronizer {
        abstract void lock();
        final boolean nonfairTryAcquire(int acquires) {
            ...
        }
        protected final boolean tryRelease(int releases){...}
        protected final boolean isHeldExclusively() {...} 
        ...
}

分析:

ReentrantLock 是独占锁,所以说需要实现抽象类 AbstractQueuedSynchronizer 中的两个方法: tryRelease(int releases)tryAcquire(int acquires)
从上面可以看出,它只实现了其中一个 tryRelease,其实 tryAcquire 是在子类中实现了。Sync有两个子类,分别是:

static final class NonfairSync extends Sync {...}
static final class FairSync extends Sync {...}

即非公平锁和公平锁的组件。
1、非公平锁:

static final class NonfairSync extends Sync {
        /**
          * 1)首先基于CAS将state(锁数量)从0设置为1,如果设置成功,设置当前线程为独占锁的线程;-->请求成功-->第一次插队
          * 2)如果设置失败(即当前的锁数量可能已经为1了,即在尝试的过程中,已经被其他线程先一步占有了锁),这个时候当前线程执行acquire(1)方法
          */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
}

分析:
Sync实现了 tryRealease 方法。在子类 NonfairSync 中,实现了 tryAcquire ,它是以非公平的方式获取锁。上面的acquire()函数在AQS中已经实现了,其中就调用了这里实现的tryAcquire()方法。
2、公平锁:

static final class FairSync extends Sync {
    final void lock() {
        acquire(1);
    }
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        //c为0的时候可以获取锁
        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;
    }
}

分析:
在FairSync中,也同样实现了tryAcquire(),它是以公平的方式获取锁。注意和 Sync 中的tryAcquire()作比较。lock()里面的acquire(1)方法在AQS中已经实现了,其中就调用了这里实现的tryAcquire()方法。
好了,至此上面所说的两个函数都实现了: tryReleasetryAcquire

三、具体实现

既然Sync组件已经写好了,那么ReentrantLock中的方法就可以使用它了。上面说到,ReentrantLock依赖组件Sync,即:

public class ReentrantLock implements Lock {
    ...
    private final Sync sync;
    ...
}

下面看一下ReentrantLock的具体实现:
1、构造函数:有两个,默认是非公平的。

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

2、获得锁:

public void lock() {
    sync.lock();
}
public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}
public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}
 public boolean tryLock(long timeout, TimeUnit unit)  throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}   

3、释放锁

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

4、条件变量

public Condition newCondition() {
    return sync.newCondition();
}

5、锁相关的工具性质的方法

public int getHoldCount() {
    return sync.getHoldCount();
}
public boolean isHeldByCurrentThread() {
    return sync.isHeldExclusively();
}
public boolean isLocked() {
    return sync.isLocked();
}
public final boolean isFair() {
    return sync instanceof FairSync;
}
protected Thread getOwner() {
    return sync.getOwner();
}
public final boolean hasQueuedThreads() {
    return sync.hasQueuedThreads();
}
public final boolean hasQueuedThread(Thread thread) {
    return sync.isQueued(thread);
}
public final int getQueueLength() {
    return sync.getQueueLength();
}
protected Collection<Thread> getQueuedThreads() {
    return sync.getQueuedThreads();
}

6、条件变量相关工具类方法

public boolean hasWaiters(Condition condition) {
    if (condition == null)
        throw new NullPointerException();
    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
    return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
public int getWaitQueueLength(Condition condition) {
    if (condition == null)
        throw new NullPointerException();
    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
        throw new IllegalArgumentException("not owner");
    return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
protected Collection<Thread> getWaitingThreads(Condition condition) {
    if (condition == null)
        throw new NullPointerException();
    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
        throw new IllegalArgumentException("not owner");
    return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}

可以看到,ReentrantLock方法的实现全部是依靠Sync的方法。而Sync又是继承了AQS,下面是整个的一个类图。


ReentrantLock类图

这篇文章只是分析个大概,并没有去详细剖析,主要是为了了解ReentrantLock的大致结构,掌握大局。OK。就先到这吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Lock.lock/unlock 接上篇,这篇从Lock.lock/unlock开始。特别说明在没有特殊情况下所有...
    raincoffee阅读 178评论 0 0
  • ReadWriteLock 从这一节开始介绍锁里面的最后一个工具:读写锁(ReadWriteLock)。 Reen...
    raincoffee阅读 652评论 0 1
  • 作者: 一字马胡 转载标志 【2017-11-03】 更新日志 前言 在java中,锁是实现并发的关键组件,多个...
    一字马胡阅读 44,189评论 1 32
  • ReentranLock从字面上理解就是可重入锁,它支持同一个线程对资源的重复加锁,也是我们平时在处理java并发...
    Justlearn阅读 1,671评论 1 5
  • ReentrantLock和synchronized一样加锁方式,独占的获取同步的对象锁。 1. 简介 R...
    Skymiles阅读 1,235评论 0 1