ReenterLock内部是怎么实现的

ReentrantLock内部有公平锁和非公平锁两种,而这两种锁都是基于AQS同步器实现的。AQS同步器太难看懂,先简单看下ReentrantLock的源码,再反推回去看AQS。

 

公平锁 VS 非公平锁:

1、公平锁能保证:老的线程排队使用锁,新线程仍然排队使用锁。

2、非公平锁保证:老的线程排队使用锁;但是无法保证新线程抢占已经在排队的线程的锁。

 

在ReentrantLock中,tryAcquire是公平锁和非公平锁实现的区别:

在公平锁中,每一次的tryAcquire都会检查CLH队列中是否仍有前驱的元素,如果仍然有那么继续等待,通过这种方式来保证先来先服务的原则。

而非公平锁,首先是检查并设置锁的状态,这种方式会出现即使队列中有等待的线程,但是新的线程仍然会与排队线程中的对头线程竞争(但是排队的线程是先来先服务的),所以新的线程可能会抢占已经在排队的线程的锁,这样就无法保证先来先服务,但是已经等待的线程们是仍然保证先来先服务。

 

非公平锁

默认构造函数:

默认就是使用的非公平锁(估计是因为非公平锁效率高吧)。

 

非公平锁加锁:lock()

  1. 首先使用CAS的方式将state设置为1,1代表当前线程获取了一次,并将当前线程设置为独占。也就是说ReentrantLock内部的非公平锁是一个独占锁。(其实从下面的tryAcquire()就可以看出来它是一个独占锁,AQS同步器独占锁抢占的命名就是这个)
  2. 如果状态设置未成功,则调用AQS类中的acquire(1)进行锁的强占(AQS中详细的怎么运行的后续文章分析吧)。acquire(1)会首先执行自定义的锁强占逻辑,不成功则执行由它定义的后续逻辑。记得内部会设置强占的线程放到队列里面,这不就违反了公平的逻辑么?而且放到队里里面的话锁会自旋,有没有不自旋的方法?

 

看下它自定义的锁抢占方法:nonfairTryAcquire(int acquires)

我将它分成了上下两部分:

  1. 如果当前的state=0,表示锁被释放了,那么仍然通过CAS的方式将自己设置进去。
  2. 如果还是当前线程来强占锁,那么state+1,这就是重入的逻辑,侧面也说明了AQS类没有实现重入逻辑

 

释放锁:unlock(),只有一个方法,看来公平锁和非公平锁释放的逻辑是一致的

调用的是AQS类中的释放独占锁的逻辑,我们稍微看下AQS里面怎么实现的:

其实就是调用用户自身定义的tryRelease()逻辑,然后再做一些收尾工作。那么久看下自定义的释放锁的方法。

tryRelease(int releases):

其实核心就这句话,lock几次就要unlock几次,线程不在占有锁就是state减到0的时候。看到这里还不明白的一点是非公平怎么实现的这个要看AQS了

 

 

公平锁:

构造函数传入true:

 

看下它加锁的逻辑:lock()

和非公平锁是一样的,底层调用的还是AQS的逻辑,只是自定义的加锁的方式不一样,并且它也是实现的独占锁的接口,那就是说ReentrantLock都是独占锁

和非公平锁唯一不同的是,它也有Queue的概念,抢占的线程是放入到队列中,每次从队列的头部获取线程,这个线程来获取。至于重入的概念和非公平锁是一致。

 

ReentrantLock类中还有一个newCondition()方法,但是这个好像不是给它自己本身用的,而是给对象用的

可以参考我分析CyclicBarrier那篇文章,这个类中CyclicBarrier类中就是用来判断一组对象是不是达到了某种条件,额…后面看的越多估计会理解的越深一点。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值