ReentrantLock源码分析

ReentrantLock是什么

ReetrantLock是java.util.concurrent包下的解决并发锁,底层通过继承AQS来实现可重入的公平锁和非公平锁,默认是非公平锁,可以通过构造方法传入true来创建公平锁。公平锁是在非公平锁基础上新加了个队列,所以本篇只介绍公平锁

ReentrantLock加锁过程

加锁过程可以分为3步:
1.调用tryAcquire()方法尝试获取锁,若获取到了,再查看AQS队列是否有线程排队,若没有排队或当前线程在队列的第二个位置(队列的第二个node为当前线程),则尝试加锁,若加锁成功,加锁流程结束,不会继续往下运行。若加锁失败,则执行第二步。
2.调用addWaiter()方法入队,若尾结点尾空则创建一个空的node对象放入队列的的第一个结点,为保证线程安全,通过cas和自旋的方式,将当前节点插入队列的尾部。
3.调用acquireQueued()方法获取队列,依旧判断当前线程是否在队列的第二个位置,如果是则再次尝试获取锁,若获取不到或者当前线程的节点不在队列的第二个位置,则改变上一个节点的waitStatus为-1,在自旋第二次时调用LockSupport.pack()方法阻塞当前线程。

ReentrantLock解锁过程

将当前现场的status状态-1后用cas修改,然后调用LockSupport.unpack()方法唤醒AQS列表当前节点的下一个节点的线程。

公平锁加锁源码分析

ReentrantLock的lock()方法,通过调用AQS的acquire()方法来实现,而AQS中的acquire()方法有如下三步:

1.tryAcquire()方法尝试获取锁

AQS中的tryAcquire()方法是个空壳方法,需要子类去实现,所以看下ReentrantLock中的公平锁FairSync是如何实现的:

假设A,B线程同时获取锁
A:
1.查看锁是否被人获取,并没有
2.能否找到队列的上一个成员,并不能
3.通过CAS改变锁状态
4.记录占用锁的线程为当前线程,返回true

此时B尝试获取锁步骤:
1.发现锁被人获取了
2.查看占用锁的线程是否为当前线程,并不是(这里是重入锁的体现)
3.返回false

2.addWaiter()方法:加入队列

此方法是AQS提供的入队方法,因为final修饰不可重写
同样是上面两个线程A和B
A:返回因为获取锁方法返回true,所以不会执行此方法
B:
1.创建一个存放当前线程的Node
2.发现AQS的尾结点为null
3.为AQS头结点创建一个空属性的Node,并让尾结点也指向它
4.让当前线程的节点的prev属性指向那个空节点,修改AQS的尾结点为当前节点,修改AQS头部的空属性节点的next属性为当前节点,返回当前节点
addWaiter方法调用结束,此时AQS的数据结构如图所示:

AQS结构图

3.调用acquireQueued()方法获取队列

A:依旧不会执行
B:
1.发现当前节点的前任节点是AQS的头节点,则再次调用tryAcquire()方法 尝试获取锁,假设A线程为解锁,则获取不到
2.调用shouldParkAfterFailedAcquire()方法,判断前节点的waitStatus是否为-1,若为-1则返回true。不为-1则设置-1,返回false
3.再次进入for循环,进入步骤1)和步骤2),此时shouldParkAfterFailedAcquire()方法返回false,执行parkAndCheckInterrupt()方法,执行LockSupport.park()方法让当前线程阻塞(Blocked)

4.selfInterrupt()的作用

ReentrantLock可以用lockInterruptibly处理打断,例如当前线程被Interrupt后,当前线程会从阻塞状态(blocked)转换为就绪状态(runnable ),lockInterruptibly()方法里发现当前线程被标记为打断则会抛出InterruptedException。我们的selfInterrupt方法会保证使用lock锁打断状态不会改变。

3.总结

ReentrantLock通过实现AQS,底层使用CAS和自旋的方式修改AQS的state状态进行加解锁,使用LockSupport.pack和LockSupport.unpack进行阻塞和唤醒线程,公平锁则是通过将排队的线程放入到AQS双向队列中排队来实现。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值