【图解】一文搞定ReentrantLock加锁、解锁过程

一、加锁

加锁用的是lock方法,首先从代码分析入手,实现类都大差不差的,以非公平锁的实现为例

一层看起来比较简单,首先使用CAS进行更新锁状态,如果成功了,则调用 setExclusiveOwnerThread()方法,将锁的拥有者设置为当前线程,如果CAS更新失败,则调用acquire(1)方法进行获取锁操作,再点进去看下acquire()方法实现

可以看到里面一共有4个方法,别着急,我们来逐个分析

①首先是非公平锁的tryAcquire()方法

这里我们选择非公平锁的实现类

再点进去

首先获取当前线程和state状态值,如果state = 0,说明是没有线程持有当前锁,尝试使用CAS将状态值设置为1,如果设置成功,说明锁持有成功,将锁拥有者设置为当前线程,如果state不为0,但是锁的持有者是当前线程,说明是重入锁,重新计算state,如果state小于0,抛出异常,否则更新state值 = state +1

总结一下:此方法用来判断是否能拿到锁,一共两种情况可以拿到锁,一种是state = 0,说明没现成持有锁,另一种是锁的拥有者是当前线程,说明是可重入锁,其他情况返回false

②再来看第二个方法addWaiter(Node mode)

首先将当前线程封装成一个node节点,首先判断tail节点如果不为空,将当前节点的前驱节点设置为tail,然后用CAS尝试更新tail指向当前节点,如果更新成功则将tail的后置节点指向当前节点,最后返回当前节点,如果tail节点为空,将当前节点进行入队操作enq(node)

可以看到这里是一个死循环,首先判断tail节点如果为空,则用CAS尝试设置head头节点,如果操作成功,则将head节点赋值给tail节点,如果tail节点不为空,将当前节点的前驱节点指向tail节点,然后通过CAS尝试将tail节点设置为当前节点,如果操作成功,则将tail节点指向当前节点

总结一下:举个例子,比如线程t1持有锁,此时线程t2调用了tryAcquire()方法,最终进入enq入队操作,第一次进入循环,t = null,所以走第一层循环,设置上tail节点= head节点,第二次进入循环,t !=null,所以最终将当前节点的prev指向tail节点,tail节点的后直节点next指向当前节点

③接下来看第三个方法acquireQueued()

首先拿到node的前置节点p,如果p是头节点,则调用tryAcquire方法尝试再获取一次锁,如果获取成功,将当前节点设置为头结点,将当前节点的后置节点next设置为null,这个主要是为了方便gc回收,然后返回中断标记,否则如果获取锁失败,则更新队列中的节点状态,并阻塞当前线程

总结一下:这个方法主要实现了一个排队思想,如果当前节点前一个节点是头结点,则可以尝试获取锁操作,如果获取到了,就将当前节点设置为头节点,后一个节点设置为null,如果前一个节点不是头结点继续排队,进行阻塞④最后是

④最后是selfInterrupt方法 

这个方法比较简单,就是当前线程调用了一次中断操作

二、解锁

解锁用的是unLock方法

首先试图释放锁,如果返回true,则获取头结点head,如果头结点不为空,并且state状态不为0,唤醒线程,首先看下tryRelease()方法怎么实现的

计算最新的state值,然后判断当前线程是否是锁的持有者,如果不是,抛出异常,定义一个完全释放变量free,如果新state值为0,说明完全释放了,并且将锁的持有者设为null,更新state状态,返回锁完全释放变量free

如果方法返回true,则会调用unparkSuccessor()方法

首先判断头结点的state状态,如果小于0,那就是-1,调用CAS方法跟新state值为0,然后获取node的下一个后驱节点,若后驱节点为空或者state大于0也就是线程被取消了,那么就往前遍历找ws <0的最前面的节点,然后唤醒

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值