ReentrantLock锁与AQS的联系

请先看——————>AQS的简单说明

        ReentrantLock底层是基于AQS实现的,在并发编程中可以实现公平锁非公平锁来对同步资源进行控制,默认是非公平锁,并且是可重入锁。  

1.ReentrantLock的体系关联结构

2.构造方法

 可以发现ReentrantLock的非公平锁和公平锁实际是NonfairSync()和FairSync()这两个类来实现的。

3.非公平锁和公平锁的实际区别

因为sync中的lock()方法是抽象方法,所以NonfairSync和FairSync类里面会重写lock()方法。  

 

        发现在调用lock方法的唯一区别就是,非公平锁会先尝试CAS去修改状态来抢占锁,如果修改成功,则抢占锁成功并返回,如果没有修改成功,则调用acquire(1)方法。而公平锁直接是调用acquire(1)方法。  

4.非公平锁的实现

4.1tryAcquire()方法

进入到acquire方法后,先调用tryAcquire(1)方法............  

         发现此方法内还是要进行尝试抢占锁,如果此时正好state状态为0了,那么CAS进行尝试修改状态,如果成功直接返回。还会判断正在占用锁的线程和当前线程是不是同一个,如果是,则证明是要重入锁,也返回true,如果这两个都没有成功,则返回false。

4.2公平锁和非公平锁在tryAcquire方法中的区别

        公平锁的tryAcquire()方法中,就算此刻状态变为0了,不会直接CAS,而是会先判断FIFO队列中是否有等待的线程,如果有,那么就不进行CAS操作了,因为要保证公平!  

4.3addwaiter()方法

需要注意的是,在双向链表中,第一个结点为虚结点(也叫做哨兵结点),只是占位用的,所以真正有用的数据结点是从第二个结点开始的。

进入到addwaiter()方法,当双向链表中尾指针为null时,需要进行初始化,创建虚结点并将封装线程的Node结点入队。当尾指针不为null时,将封装线程的Node结点入队,并将尾指针指向Node结点。

执行完毕后返回加入的Node结点。

4.4acquireQueued()方法

 

        我们将Node入队之后,执行acquireQueued方法,先拿到Node的前驱结点,判断是否为虚拟头结点,如果是,那么直接尝试tryAcquire()去获取锁,如果获取到了,将虚拟头结点指向Node,原来的虚拟头结点指向null,等待GC回收即可,但是如果Node的前驱结点不是虚拟头结点或没获取到锁,那么修改其前驱结点的状态直到为SIGNAL,前驱结点的状态修改完后,然后利用LockSuppor.park()将当前Node进行阻塞。

        那现在我们的好奇心飙升了,加入的Node将它的前驱结点状态修改了,然后自己又阻塞了,那么Node什么时候唤醒unPark呢?一个线程占用锁后,调用了unlock()方法解锁,那么unlock()方法有什么猫腻呢?

4.5unlock()方法

 

4.6unlock后发生的一些事情

        一个线程释放锁后,会唤醒虚拟头结点后的第一个结点,唤醒之后,还在acquireQueued()方法中,然后进行for循环,因为此时锁此时已经释放了,此时唤醒的Node的前驱就是虚拟头结点,调用tryAcquire()方法去获取锁,获取到后将虚拟头结点指向Node,原来的虚拟头结点指向null,等待GC回收即可。队列中一直后面的线程Node就还处于阻塞的状态。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值