JUC 之 ReentrantLock 源码解析

JUC 之 ReentrantLock 源码解析

前面我们学习了 AQS 的源码,了解了 AQS 的实现原理,为我们后面即将学习的 ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore 等奠定了扎实的基础。Java 中同步器的实现均离不开 AQS 的支持。那么下面我们就从 ReentrantLock 开始逐一进行讲解。

首先我们先来看看类的继承体系,通过源码我们发现 ReentrantLock 实现了 Lock 接口,通过内部类的方式实现AQS的功能。先来看下 Lock 接口信息,通过源码我们可以清晰看到 Lock 接口提供了哪些功能,提供了 获取锁、释放锁以及 Condition 条件的创建功能。

Lock 接口

public interface Lock {
	// 获取锁,获取失败阻塞等待
    void lock();
	// 获取锁,获取失败阻塞等待,阻塞过程中可被中断唤醒
    void lockInterruptibly() throws InterruptedException;
	// 尝试获取锁,获取不到立即返回
    boolean tryLock();
	// 尝试获取锁,获取不到,等待 time 时间后还是获取不到则立即返回
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
	// 释放锁
    void unlock();
	// 创建一个等待条件
    Condition newCondition();
}

Sync 内部类

ReentrantLock 的锁实现就是借助该内部类实现的,ReentrantLock 实现了 公平锁与非公平锁,Sync 抽象类提供了,非公平锁的获取锁实现以及释放锁的实现(公平与非公平通用逻辑)。

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

    abstract void lock(); // 抽象方法,有子类实现
	// 非公平锁的实现
    final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();// 取到当先线程信息
        int c = getState();// 获取当前 state 信息(AQS中的 state 变量)
        if (c == 0) {// 此判断表明暂时没有现成持有锁,CAS 抢锁,CAS 成功设置线程信息
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {// 持有锁的线程是当前线程,表明锁重入,对 state 变量加 1 
            int nextc = c + acquires;
            if (nextc < 0) // int 值溢出了
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
	// 释放锁,逻辑很简单,还原 state 值即可
    protected final boolean tryRelease(int releases) {
        int c = getState() - releases;
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;
        if (c == 0) {
            free = true;
            setExclusiveOwnerThread(null);
        }
        setState(c);
        return free;
    }
	// 创建条件对象信息
    final ConditionObject newCondition() {
        return new ConditionObject();
    }
	...
}

FairSync 公平锁

继承自 Sync 抽象类,实现了 AQS 的 tryAcquire 方法

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

    final void lock() {
        acquire(1);
    }
	// AQS 中定义的模板函数
    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;
    }
}

NonfairSync 非公平锁

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;
	// 获取锁实现
    final void lock() {
        // 不管有没有线程在等待,先抢,抢不到调用 acquire 方法进入 AQS 中
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

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

ReentrantLock 的实现依赖于 Sync 内部类,所有的实现均交由 Sync 来实现。ReentrantLock 本身并没有完成同步器的功能,只是提供了操作同步器的入口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值