Java中的ReentrantLock的原理和部分源码分析

本文详细介绍了Java并发包中ReentrantLock的实现原理,包括非公平锁和公平锁的工作流程,以及锁的获取与释放过程。通过深入剖析AbstractQueuedSynchronizer的机制,帮助读者理解独占式锁的运作机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在研究jdk中的锁。下面我们说一下。

Java并发包中提供了Lock接口用来实现锁功能。提供了与synchronized类似的同步功能。只是要在使用时需要显示地获取锁和释放锁,虽然缺少隐式获取锁的便捷性,但是拥有

锁获取与释放的可操作性性,可中断的获取锁以及超时获取锁等多种synchronized不具备的同步特性。

1、队列同步器

      队列同步器AbstractQueuedSynchronizer,是用来构建锁或者其他同步组件的基本框架,使用一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。

同步器既可以支持独占式地获取同步状态,也可以支持共享式地获取同步状态。

下面我们来说一下    独占式    获取锁状态的原理

  独占式获取锁会导致其他线程争抢这个一个锁资源的时候被阻塞


ReentrantLock------>调用lock()----------默认非公平锁------->在ReentrantLock内部实现的非公平同步器NonfairSync中调用----lock()如下图


如果获取锁失败--->调用父类AbstractQueuedSynchronizer同步器中的acquire(int arg)方法如图


上图的逻辑:我尝试获取下锁,如果能获取到,后面的acquireQueued()就不用执行,直接拿到锁,如果没有拿到锁,返回false。那么就会执行后面的将当前线程构造成一个节点Node放到同步队列中。我们看下如何tryAcquire(arg)


tryAcquire(arg)内部就调用了上图的这个方法。说明看图里的内容。---------->如果返回fasle------就要将当前线程构造成一个Node节点放到同步队列里---->添加节点的逻辑如下图


acquireQueued(addWaiter(Node.EXCLUSIVE), arg) 里的addWaiter()方法就是将当前线程构造成一个节点Node.放到同步队列中,Node就是当前线程的一个引用

acquireQueued()。获取队列,是通过自旋来判断该node何时拿到锁并返回



如何做到阻塞呢?其实线程在没有拿到锁的时候,其实是一直在运行的,一直在跑上面的自旋判断,没拿到锁就相当于一直阻塞在队列里并一直循环判断。停在了lock()锁获取这里

以上是非公平锁的实现原理;

下面我看下公平锁的实现。

公平锁与非公平锁的区别就只是在调用公平锁的时候,没有直接CAS原子操作去尝试设置修改状态拿锁,而是,直接调用的acquire(1)--如图



锁的释放:

    大致原理:获取到同步器的state值 c,然后减去1或者传过来的参数arg.,如果c-1=0或者c-arg=0;那么就将同步器所持的线程置为null.并将c设置成0;如图源码


这就是独占式锁的大致原理。如有不对的地方请指导。

--我觉得同步队列还是有必要研究下的。




 




### AQS 底层实现机制 AQS(AbstractQueuedSynchronizer),即抽象队列同步器,是构建其他同步组件的基础框架。其核心在于使用了一个FIFO队列来管理线程获取释放共享资源的过程[^1]。 #### 原子操作与状态管理 为了保证多线程环境下的安全性,AQS利用了CPU级别的原子指令——比较并交换(Compare-and-Swap, CAS)。这种机制允许程序在不加的情况下完成对内存位置的操作,从而提高了性能效率。具体来说,在Java中可以通过`Unsafe.compareAndSwapInt()`方法来执行CAS操作,确保每次修改state变量时都能保持数据的一致性完整性。 #### 阻塞/唤醒策略 当某个线程尝试获得失败后会被挂起,并加入到由节点组成的等待队列之中。这里涉及到两个重要的辅助类:`Node`用于表示单个排队中的成员;`LockSupport.park/unpark`则负责实际的线程暂停与恢复工作。每当持有者释放之后,会按照先进先出的原则挑选下一个候选者继续运行。 ### ReentrantLock 源码解析 作为AQS的一个典型应用实例,ReentrantLock实现了可重入性的互斥定功能。下面将围绕着几个方面展开讨论: #### 构造函数选项 提供了两种不同类型的构造方,默认情况下是非公平模下初始化对象;如果指定了参数true,则开启公平竞争模,使得后续请求遵循严格的顺序原则[^2]。 ```java public ReentrantLock() { sync = new NonfairSync(); } public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } ``` #### 获取过程 对于非公平而言,当前线程可以直接尝试通过CAS更新state字段值为1,成功的话意味着立即获得了所有权而不必经历漫长的等待流程。相反地,若是处于公平状态下或是存在前驱节点尚未处理完毕的情况,则需调用acquireQueued方法进入休眠直至被激活为止。 ```java final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } ``` #### 条件变量支持 除了基本的独占访问外,ReentrantLock还引入了Condition接口用来模拟传统意义上Object.wait()/notify()的行为。每一个condition关联着独立的条件队列,这有助于更灵活地控制协作逻辑。 ```java private final ConditionObject condition; public Condition newCondition() { return condition; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值