ReentrantLock梳理和总结

一、ReentrantLock的lock()梳理

首先贴下lock()源码调用时序图:

 源码:

  1. 首先通过cas抢占锁
  2. 如果抢占失败,则执行acquire()方法 

  1. tryAcquire方法:再抢占一次锁。会走到nofairTryAcquire方法,nofairTryAcquire方法的主要作用是再次抢占锁。分为两种情况,state为0和state不为0。state为0表示没有重入,state不为0且当前抢占锁的线程为当前线程,表示重入了锁,state需要+1。
  2. addWaiter方法:如果步骤1抢占锁失败,则需要将当前线程包装成Node,放到aqs同步队列的尾部。
  3. acquireQueued:在同步队列中抢占锁,只有head节点才能抢占锁,也就是说,在同步队列中,节点抢占锁的顺序是由链表的前往后。acquireQueued方法是包含一个死循环的,出口是只能是当前节点是头节点并抢到了锁,否则就挂起线程。

上述方法的具体代码我就不贴了,之前的文章分析过。 直接贴上之前文章的图解吧:

 二、ReentrantLock的unlock()梳理

 unlock方法主要做了两个动作:

  1. 释放锁,即state-1,并且exclusiveOwnerThread属性设置为null。
  2. 唤醒离head节点最近的waitStatus<=0的节点线程

三、加锁和释放锁流程图

四、公平锁和非公平锁的区别

  • 非公平锁会先进行一次cas抢占锁,没抢占到才加入aqs队列。
  • 公平锁,则会判断aqs队列当前节点是否有前驱节点,如果返回true,则表示有线程比当前线程更早地请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。

五、在队列同步器中,同步队列为什么是双向链表,而等待队列是单链表?

在《Java并发编程的艺术》一书中有这样一段话: 

在队列同步器中,头节点是成功获取到同步状态的节点,而头节点的线程释放了同步状态后,将会唤醒其他后续节点,后继节点的线程被唤醒后需要检查自己的前驱节点是否是头节点,如果是则尝试获取同步状态。

 所以为了能让后继节点获取到其前驱节点,同步队列便设置为双向链表,而等待队列没有这样的需求,就为单链表。

六、请简述AQS原理

简述AQS原理

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值