ReentrantLock源码走读分析

本文详细分析了ReentrantLock的公平锁和非公平锁的区别,从构造方法到核心的lock实现。公平锁首先尝试获取锁,失败则根据AQS的hasQueuedPredecessors()判断是否需要等待;非公平锁则不进行此判断,直接尝试获取锁。关键方法如tryAcquire()使用CAS操作保证线程安全,而AQS的acquireQueued()用于处理获取锁失败的情况,将线程加入等待队列。
摘要由CSDN通过智能技术生成

首先, ReentrantLock作为一种常用的锁,可以通过构造方法中穿ture来指定是公平锁,还是非公平锁,因此从源码上来分析公平锁和分公平锁有什么区别:

从构造方法可以看出,公平锁非公平锁的区分主要是看ReentrantLock的一个属性类sync的实现来决定的,当公平锁的时候,实现类是FairSync,非公平锁的时候,实现类是NonfairSync

 

  • NonfairSync的类继承关系
    1422237-20180805183109489-1524063793.png

  • FairSync的类继承关系
    1422237-20180805183410668-314295960.png

  • 首先从lock方法进入,可以发现,ReentrantLock的lock方法实现,最终是由sync类来实现的

  • 首先我们去看公平锁的lock实现,从代码走读可以看出,公平锁首先会调用尝试获取锁的方法,当获取锁失败,并且等待队列满了的情况下,当前线程便会被中断

  • 其中我们可以发现,acquire方法是AbstractQueuedSynchronizer类的,也就是AQS,所以lock的底层是由AQS实现的

我们再来看公平锁的tryAcquire()方法实现,走读代码,首先会获取当前线程,然后获取AQS中的status,也就是锁的状态,当status为0时,锁未被占有,通过cas(compareAndSetState,其底层实现是由unsafe类实现的,最终native修饰,即c语言编写,最终通过cup原语支持,以及内存一致性协议),将锁的拥有者设置为当前线程,从而完成了加锁的功能;如果当前锁状态是被占有的,则判断占有锁的线程是不是当前线程,如果是当前线程,则status再加1,从而达到ReentrantLock可重入的目的

  •  

    hasQueuedPredecessors()方法是区别公平锁与非公平锁最主要的方法,其中主要是判断等待队列中是否有线程等待获取锁,以及当前线程是否排在队列第一位,如果不是,则不会尝试加锁

     

  • status是通过volatile修饰的,可以保证线程之间的可见性,保证了多线程情况下的锁竞争

  • 如果尝试获取锁失败的话,则会调用acquireQueued方法放入一个等待队列中,队列的实现原理是一个volatile修饰的Node类,也就是一个双向列表,将当前线程加在链表的最后一位

  • 再来看非公平锁的实现方式,其中实现方式大致相同,主要区别在于没有判断hasQueuedPredecessors()方法的返回值,也就是当前线程不管是不是队列中的第一个,或者队列为空,都直接去获取锁

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值