java面试--reentrantLock可重入锁

可重入锁(可以对同一个锁进行重复加锁)。ReentrantLock自 JDK 1.5 被引入,功能上与synchronized关键字类似。ReentrantLock 内部是基于 AbstractQueuedSynchronizer(以下简称AQS)实现的。ReentrantLock 在功能上比 synchronized 更为丰富。比如 ReentrantLock 在加锁期间,可响应中断,可设置超时等。

ReenTrantLock与synchronized对比:

特性synchronizedReentrantLock相同
可重入 
响应中断 
超时等待 
公平锁 
非公平锁 
是否可尝试加锁 
是否是Java内置特性 
自动获取/释放锁 
对异常的处理自动释放锁需手动释放锁 

synchronized 使用的是对象或类进行加锁,而 ReentrantLock 内部是通过 AQS 中的同步队列进行加锁。除此之外,ReentrantLock提供了丰富的接口用于获取锁的状态。比如可以通过isLocked()查询 ReentrantLock 对象是否处于锁定状态, 也可以通过getHoldCount()获取 ReentrantLock 的加锁次数,也就是重入次数等。而 synchronized 仅支持通过Thread.holdsLock查询当前线程是否持有锁。

与Synchronized的差异:

  1. ReentrantLock 通过方法 lock()与unlock()来进行加锁与解锁操作,与synchronized 会 被 JVM 自动解锁机制不同,ReentrantLock 加锁后需要手动进行解锁。为了避免程序出 现异常而无法正常解锁的情况,使用 ReentrantLock 必须在 finally 控制块中进行解锁操 作。
  2. ReentrantLock相比synchronized的优势是等待可中断(会在获取所得时候,判断是否为可中断)、公平锁、多个锁。这种情况下需要 使用ReentrantLock

ReenTrantLock的特性:

1、可重入性(通过AQS中的states属性来进行设置)

2、公平锁(线程在同步队列中通过 FIFO 的方式获取锁,每个线程最终都能获取锁)与非公平锁(线程会通过“插队”的方式去抢占锁,抢不到的则进入同步队列进行排队)

非公平锁性能高?在激烈竞争的情况下,非公平锁的性能高于公平锁的性能的一个原因是:在恢复一个被挂起的线程与该线程真正开始运行之间存在着严重的延迟。假设线程 A 持有一个锁,并且线程 B 请求这个锁。由于这个线程已经被线程 A 持有,因此 B 将被挂起。当 A 释放锁时,B 将被唤醒,因此会再次尝试获取锁。与此同时,如果 C 也请求这个锁,那么 C 很有可能会在 B 被完全唤醒前获得、使用以及释放这个锁。这样的情况时一种“双赢”的局面:B 获得锁的时刻并没有推迟,C 更早的获得了锁,并且吞吐量也获得了提高。另一个可能的原因。即公平锁线程切换次数要比非公平锁线程切换次数多得多,因此效率上要低一些。

 

ReentrantLock源码分析:

1、结构

ReenTrantLock是基于AQS来实现的,AQS很好的封装了同步队列的管理,线程的阻塞与唤醒等操作。

Syns是一个静态抽象类,继承了AQS。而公平锁(FairSync)与非公平锁(NonfairSync)则继承自Sync。ReenTrantLock的主要逻辑都是基于这几个累不累来实现的、

2、锁的获取

点击查看reentrantLock详细信息

非公平锁:

其加锁的步骤大致如下:

  1. 首先应该尝试获取锁,如果没有线程占用锁(status为0),则获取锁成功,设置独占锁为当前线程(调用setExclusiveOwnerThread(current))来将当前线程设置为独占锁),接着判断占有锁的线程是否为当前线程(如果是,则修改status,设置为重入锁),否则的话就返回false表示尝试获取锁失败。

  2. 接着将申请锁的线程放入到CLH对类中进行等待(先将节点初始化,再将结点加入到为节点当中{通过CAS+自选}),此时线程未获取到锁的线程入队

  3. 最后,将线程挂起。这个操作是让已经入队的线程尝试获取锁,若成功则获取锁;若失败则线程会被挂起(要求其前驱结点为singal状态)。直到获取到锁(通过自旋+CAS)

流程图:

1、公平锁

公平锁和非公平锁不同之处在于,公平锁在获取锁的时候,不会先去检查state状态(避免抢占),而是直接执行aqcuire(1)。

释放所:

流程大致为先尝试释放锁,若释放成功,那么查看头结点的状态是否为SIGNAL,如果是则唤醒头结点的下个节点关联的线程,如果释放失败那么返回false表示解锁失败。当前释放锁的线程若不持有锁,则抛出异常。若持有锁,计算释放后的state值是否为0,若为0表示锁已经被成功释放,并且则清空独占线程,最后更新state值,返回当前状态是否已经释放

 

于2020/09/29完成

参考链接:

https://www.imooc.com/article/28934   

https://blog.csdn.net/fuyuwei2015/article/details/83719444

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ReentrantLockJava中的一个可重入锁,它提供了与synchronized关键字类似的功能,但更加灵活和强大。下面是一些与ReentrantLock锁相关的面试题及其答案: 1. 什么是可重入锁可重入锁是指同一个线程可以多次获得同一个锁,而不会造成死锁。ReentrantLock就是一个可重入锁。 2. ReentrantLock相对于synchronized关键字有什么优势? 相对于synchronized关键字,ReentrantLock提供了更多的功能和灵活性。它可以实现公平锁和非公平锁,支持多个条件变量,可以中断等待锁的线程,还可以尝试获取锁等。 3. ReentrantLock如何实现可重入性? ReentrantLock通过记录持有锁的线程和持有次数来实现可重入性。当一个线程再次获取已经持有的锁时,它的持有次数会增加,当释放锁时,持有次数会减少,只有当持有次数为0时,其他线程才能获取该锁。 4. ReentrantLock如何实现公平性和非公平性? ReentrantLock可以通过构造函数来指定是公平锁还是非公平锁。公平锁会按照线程请求的顺序来获取锁,而非公平锁则允许插队,可能会导致某些线程一直获取不到锁。 5. ReentrantLock如何实现条件变量? ReentrantLock提供了Condition接口来支持条件变量。通过调用ReentrantLock的newCondition()方法可以创建一个Condition对象,然后可以使用该对象的await()、signal()和signalAll()方法来实现线程的等待和唤醒。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值