ReentrantLock实现原理分析

类图

ReentrantLock相关类图:

这里写图片描述

  • AbstractOwnableSynchronizer类保持和获取独占线程。

  • AbstractQueuedSynchronizer,继承自AbstractOwnableSynchronizer,简称AQS,基于FIFO(First Input First Output)队列的实现。以虚拟队列的方式管理线程的锁获取与锁释放,以及各种情况下的线程中断。提供了默认的同步实现,但是获取锁和释放锁的实现定义为抽象方法,由子类实现。目的是使开发人员可以自由定义获取锁以及释放锁的方式。

  • Sync是ReentrantLock的内部抽象类,继承自AbstractQueuedSynchronizer,实现了简单的获取锁和释放锁。NonfairSync和FairSync分别表示“非公平锁”和“公平锁”,都继承于Sync,并且都是ReentrantLock的内部类。

  • ReentrantLock实现了Lock接口的lock-unlock方法,根据fair参数决定使用NonfairSync还是FairSync。

AQS

ReentrantLock实现的前提就是AbstractQueuedSynchronizer,简称AQS,是java.util.concurrent的核心,CountDownLatch、FutureTask、Semaphore、ReentrantLock等都有一个内部类是这个抽象类的子类。

Node

Node是AQS的内部类,是对每一个访问同步代码的线程的封装。不仅包括了需要同步的线程,而且也包含了每个线程的状态,比如等待解除阻塞,等待条件唤醒,已经被取消等等。同时Node还关联了前驱和后继,即prev和next。

多个Node连接起来成为了虚拟队列(因为不存在真正的队列容器将每个元素装起来所以说是虚拟的,我把它称为release队列,意思是等待释放),其实就是一个有头有尾的双向链表结构:

这里写图片描述

state

是AQS的一个成员变量,用来记录锁的持有情况:

  • 没有线程持有锁的时候,state为0

  • 当某个线程获取锁时,state的值增加,具体增加多少开发人员可自定义,默认为1,表示该锁正在被一个线程占有。

  • 当某个已经占用锁的线程再次获取到锁时,state再增长,此为重入锁

  • 当占有锁的线程释放锁时,state也要减去当初占有时传入的值,默认为1。

多个线程竞争锁的时候,state必须通过CAS进行设置,这样才能保证锁只能有一个线程持有。

Sync

NonfairSync和FairSync分别表示“非公平锁”和“公平锁”,都继承于Sync,并且都是ReentrantLock的内部类。

我们来看NonfairSync获取锁的代码:

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

        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            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;
        }

还有FairSync获取锁的代码:

        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获取锁时比FairSync中少了一个判断!hasQueuedPredecessors()hasQueuedPredecessors()中判断了是否存在等待队列,导致公平锁和非公平锁的差异如下:

  • 公平锁:公平锁讲究先来先到,线程在获取锁时,如果这个锁的等待队列中已经有线程在等待,那么当前线程就会进入等待队列中

  • 非公平锁:不管是否有等待队列,如果可以获取锁,则立刻占有锁对象

lock()与unlock()

lock()

流程图(图中的Node0和Node1在源代码中不存在,是为了方便说明清楚才添加的别称):

这里写图片描述

unlock()

流程图:

这里写图片描述

参考:
1.ReentrantLock实现原理深入探究
2.ReentrantLock的lock-unlock流程详解
3.轻松学习java可重入锁(ReentrantLock)的实现原理
4.ReentrantLock解析
5.深度解析Java8 – AbstractQueuedSynchronizer的实现分析(上)
6.ReentrantLock(重入锁)以及公平性

ReentrantLock是一个可重入,实现了Lock接口,并且支持重新进入的特性。当一个线程通过调用lock方法获取了之后,如果再次调用lock方法,该线程不会被阻塞,而是增加了重试次数。 在ReentrantLock内部,它维护了一个Sync内部类,该类实现了Lock接口的方法,并且通过调用AQS(AbstractQueuedSynchronizer)的Acquire方法来实现加的操作。具体而言,根据ReentrantLock初始化时选择的公平或非公平,Sync的Lock方法会执行相关的内部类Lock方法,最终会调用AQS的Acquire方法。 因此,ReentrantLock底层的原理是通过Sync内部类的Lock方法调用AQS的Acquire方法来实现加操作的。这一过程实现了可重入的特性,使得同一个线程可以多次获取而不会被阻塞。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [7-ReentrantLock底层原理分析](https://blog.csdn.net/weixin_45596022/article/details/113817683)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [ReentrankLock的底层原理](https://blog.csdn.net/qq_45974547/article/details/123486390)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值