JDK17 ReentrantLock 简述 lock()、unLock()

背景

  • 最近无聊翻一翻 juc ,想看 AQS 入队的是怎么入队的,由于代码量比较大,就想先看了 ReentrantLock 入队操作,然后举一反三,由于我看的是 JDK 17 的版本,与 JDK 8 可能不一样,先不去考证 JDK 8 内容,只看 JDK 17 的代码,并且只讨论 ReentrantLock 中的方法

读代码

lock()

  • 首先肯定要读 lock() 和 unLock() 两个方法,实际写代码就是用这两个完成重入锁操作
	public void lock() {
        sync.lock();
    }

肯定走这个方法了吧,当我 ctrl + 鼠标左键调到具体方法时,发现并没有这样显示:
在这里插入图片描述
而是直接跳到了

		@ReservedStackAccess
        final void lock() {
            if (!initialTryLock())
                acquire(1);
        }

这个 initialTryLock() 是一个抽象方法,而 acquire(1) 调用的是 AQS 类的方法,AQS 的类代码先不讨论,反正不管公平还是非公平锁最后都调用 acquire(),也就是入队 的简称 ;
先看 ReentrantLock 的内容,当我点击 initalTryLock() 方法时出现了,公平锁和非公平锁两个选项:
在这里插入图片描述
现在比较一下两个不同的 initialTryLock() 实现:
在 idea 中打开两个相同的类
在这里插入图片描述
两部分代码其实只有红色的部分不一样:
在这里插入图片描述
相比较之下只是公平锁多出了:

			int c = getState();
            if (c == 0) {
                if (!hasQueuedThreads()

很好理解,先获取 AQS 中 state 变量的属性,如果属性是 0,再去看线程队列中有没有人排队,没人排队再去竞争下,很显然公平锁还是讲武德的,别人在排队了,我就不去竞争了;相比较,非公平锁,来了就去竞争下,没竞争到再入队,这年轻人xxxx;

这里会有疑问,什么是 state 属性,什么是队列呢,说说我自己的理解?

  • 要从 AQS 设计说起,AQS 本身就是一个普通抽象类,与我们平时自己写的抽象类一样,里面有一个用 volatile 关键字修饰 int 类型的成员变量 state ,因为有 volatile 关键字修饰,那么多个线程都能看见这个 state ,如果多个线程竞争同一个资源时,都去参考 state 的值,这个 AQS 不就相对于一把锁了吗,当 state=0 时,代表没人竞争,代码继续执行,当 state > 0 时,代表有人持有这个资源,就去等待,等持有锁的线程执行完再去竞争资源,执行这个锁与 synchronized 相比哪个性能好先不去讨论,先看 lock 时引出的两个问题;

  • 一个是 state 是值从 0 变为大于 0 ,怎么保证原子性,另一个是当 state > 0,等待的线程去哪里等待或者叫记录他们线程信息 和 先来后到顺序;第一个问题有 cas 算法呀,第二个使用 node 队列解决, node 有一个属性 waiter 记录线程信息,队列来保证先来后到顺序;这不就行了吗

  • 当 state >1 代表什么呢,在 ReentrantLock 中代表重入次数,在 CountDownLatch 中代表倒计次数开门闩,其他的 juc 类没怎么看,就不说了;

unLock()

unLock() 代码 ReentrantLock 的公平锁和非公平锁调用的是同一套释放锁方法:

	public void unlock() {
        sync.release(1);
    }
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            signalNext(head);
            return true;
        }
        return false;
    }
    @ReservedStackAccess
    protected final boolean tryRelease(int releases) {
        int c = getState() - releases;
        if (getExclusiveOwnerThread() != Thread.currentThread())
            throw new IllegalMonitorStateException();
        boolean free = (c == 0);
        if (free)
            setExclusiveOwnerThread(null);
        setState(c);
        return free;
    }

这里就不展开说了,写的有点长了, tryRelease(arg) 就是 tryRelease(1),tryRelease(1) 就是把 AQS 中的 state 属性减 1,当减到 0 时,返回 ture,通知 AQS 队列头结点的下一个;

整体架构评价

  • 在看 JDK17 的 ReentrantLock 时我发现代码结构更精简了。以前我以为有两个内部类 FairSync 和 NonFair ,现在有多了一个 Sync 类,把 FairSync 和 NoFair 的共有属性放到了 Sync 类,首先FairSync 和 NonFairSync 都变精简了,其次方便观察实现不同:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值