ReentrantLock源码

ReentrantLock(可重入锁)

      ReentrantLock 感觉上是 Synchronized 的增强版,二者都是可重入锁,Synchronized 的特点是使用简单,一切都交给 JVM 去处理,但是在功能上比较薄弱。ReentrantLock 相比 Synchronized 在功能上更加丰富,它具有可重入、可中断、可限时、公平锁等特点,首先通过一个简单的例子了解一下它的用法:

1.1 可重入

      单线程(同一个线程)可以重复进入,但也要重复退出,如果不重复退出的话,其它线程将无法获取锁,会发生死锁的现象。由于 ReentrantLock是可重入锁,所以可以反复得到相同的一把锁,它有一个于锁相关的获取计数器,如果拥有锁的线程再次得到锁,获取计数器将会加1,然后锁被释放两次才能获得真正的释放锁,具体代码如下:

1.2 可中断

       ReentrantLock 对中断是有响应的,普通的 lock.lock()是不能响应中断,lock.lockInterruptibly() 是能够响应中断的,我们模拟一个死锁场景,然后用中断来处理死锁,具体代码如下:

上述代码 有可能会发生死锁,线程1得到锁 lock1,线程2得到锁 lock2,然后彼此又想获得对方的锁,用 jstack 命令查看代码运行情况:

可以使用中断把死锁的线程中断掉,中断后线程正常退出,具体代码如下:

1.3 可限时

       超时不能获得锁,就返回false,不会永久等待构成死锁。使用 lock.tryLock(long timeout,TimeUnit unit) 来实现可限时锁,参数为时间和单位,具体代码如下:

1.4 公平锁

      ReentrantLock无参默认构造函数构造的是非公平锁,如果想创建公平锁,那么只需要使用如下代码: 

具体源码如下:

一般意义上的锁都是非公平的,不一定先来的线程就能获取锁,后来的线程就后得到锁,不公平锁会产生饥饿现象。公平锁能够保证先来的线程先获取锁,但是公平锁的性能会比非公平锁差很多。

下面介绍一下 ReentrantLock 的实现, ReentrantLock 的实现只要有 3 部分组成:

state : CAS状态

addWaiter:等待队列

unlock:释放锁

ReentrantLock 有 3 个静态类来实现该类的功能,结构如下:

NonfairSync:非公平锁类,它的作用是在有线程请求锁时,并不能保证首先请求的线程可以拿到这个锁

FairSync:公平锁类,如果已经有线程持有锁了,那么请求线程会被放入队列中,然后按顺序请求锁

ReentrantLock 的父类 AbstractQueuedSynchronizer 中有一个  state 变量来表示同步状态:

通过 CAS 操作来设置 state 状态来获取锁,如果 state 被设置成 1,则将锁的持有者给当前线程,代码如下:

如果申请锁不成功,则会去申请,具体代码如下:

首先先去 tryAccquire 试试申请锁,因为此时可能其他线程释放了锁,如果还没有申请到锁,就执行 addWaiter ,将自己添加到等待的队列中去,addWaiter 具体代码如下:

这期间还会有多次尝试去申请锁,如果还是申请不到,就会被挂起,具体代码:

那么在 unlock 中就是释放了锁,具体代码如下:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值