ReentrantLock 源码分析

巧了我就是萌 提交于 2020-04-27 21:31:01

前言

前面用了 4 篇文章为本文分析 ReentrantLock 源码做了一些铺垫,

ReentrantLock 源码分析 - 基础知识篇

ReentrantLock 源码分析 - 并发基础类

ReentrantLock 源码分析 - AbstractQueuedSynchronizer 详解(一)

ReentrantLock 源码分析 - AbstractQueuedSynchronizer 详解(二)

赶紧趁热打铁,来看下 ReentrantLock 非公平锁的lock()方法是如何实现的。

正文

知识回顾

ReentrantLock 既可以实现非公平锁,也可以实现公平锁。

通过 ReentrantLock lock = ReentrantLock(false) 的方式可以创建一个非公平锁。

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

从上面的构造方法可以看出, 当传入 false 时,new 了个 NonfairSync 对象。

NonfairSync 类

通过查看源码,可以看出NonfairSync 继承 Sync

Sync 又是什么? 请往后看。

    static final class NonfairSync extends Sync {
     
    }

Sync 类

Sync 继承自我们熟悉的 AQS, 前面花了很多篇幅去介绍 本文会涉及 到的 AQS部分实现。Sync 中有一个nonfairTryAcquire(int acquire)方法,该方法在前面的文章中也举例说明过,

我们先跳过这段源码分析,接着往下看 :

   abstract static class Sync extends AbstractQueuedSynchronizer {
     
        // 知识回顾:前面有介绍 ReentrantLock 是可重入锁,state 表示重入次数
        final boolean nonfairTryAcquire(int acquires) {
           // 获取当前线程
            final Thread current = Thread.currentThread();
            // 获取 state
            int c = getState();
            // 如果 state == 0,表示锁未被占用,
            // 然后通过 CAS 操作,把 state + 1,标记锁被占用
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 如果锁被线程 A 占用
            // 判断当前线程是否就是线程 A
            // 如果是,就把 state +1
            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;
        }

    }

lock() 方法

回归初心,来看下 lock 的调用方式

ReentrantLock lock = new ReentrantLock(false);
lock.lock();

而 lock() 的实现如下:

   public void lock() {
        sync.lock();
    }

根据前面讲的,此时 sync = NonfairSync(),

NonfairSynclock 方法实现如下:

       final void lock() {
           // 通过 CAS 原子操作,把 state 由 0 设置为 1
            if (compareAndSetState(0, 1))
                // 设置成功,把当前线程标记为独占锁持有者
                setExclusiveOwnerThread(Thread.currentThread());
            else
               // 如果 cas 失败,表示抢占锁失败,把当前线程放入 AQS 队列,入队后,还会有一系列操作
               // AQS 的 acquire(int arg) 方法, 上文有详细讲过
                acquire(1);
        }

tryAcquire(int arg) 方法

前面提到了 AQS 的 acquire 方法中调用了 tryAcquire方法,该方法主要目的是获取锁资源, 它本身在 AQS 中是抽象方法,由具体的子类实现的(在此处就是 NonfairSync), 而 tryAcquire 方法又调用了nonfairTryAcquire方法, 这时候我们就可以 传送Sync 类 介绍部分,去阅读那段nonfairTryAcquire方法的源码

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

总结

可以看出本文内容非常少,我们前期花了大量的功夫去挖掘一些基础知识,因为 ReentrantLock 本身就是基于 AQS 实现的,而 AQS 又依赖于下面的小知识

ReentrantLock 源码分析 - 并发小知识

ReentrantLock 源码分析 - 并发基础类

因此把前面的基础打好,ReentrantLock的具体实现就很容易看懂了。

再次总结下本文主要内容:

  1. ReentrantLock 可以通过 new ReentrantLock(false)方式实现非公平锁
  2. 第 1 步 产生的结果就是 new 了一个 NonfairSync
  3. NonfairSync 本文继承自 Sync, 而 Sync 又继承自 AQS
  4. 当调用非公平锁的 lock()方法时,就是调用NonfairSynclock 方法
  5. 第 4 步就是一个抢占锁的过程
    • 抢占成功与否是根据 CAS 操作结果判定的
    • 抢占失败的线程会调用 acquire方法,继续尝试获取锁,获取失败就会被被放入 AQS 队列(具体策略看上一篇文章)
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!