ReentrantLock实现原理及源码分析,12道Android高级面试题

本文详细分析了ReentrantLock的实现原理,包括公平锁与非公平锁的构造方式,以及lock、unlock、tryLock等核心方法的工作逻辑。通过NonfairSync和FairSync静态内部类,展示了如何实现锁的重入性和公平性。同时,文章指出ReentrantLock的处理逻辑依赖于AQS(AbstractQueuedSynchronizer)的底层支持。最后,作者提醒读者,面试中Android知识点的考察往往围绕这些核心技术展开。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

public ReentrantLock() {

sync = new NonfairSync();//默认是非公平的

}

sync是ReentrantLock内部实现的一个同步组件,它是Reentrantlock的一个静态内部类,继承于AQS,后面我们再分析。

带布尔值的构造器(是否公平)

public ReentrantLock(boolean fair) {

sync = fair ? new FairSync() : new NonfairSync();//fair为true,公平锁;反之,非公平锁

}

看到了吧,此处可以指定是否采用公平锁,FailSync和NonFailSync亦为Reentrantlock的静态内部类,都继承于Sync

再来看看几个我们常用到的方法

lock()

public void lock() {

sync.lock();//代理到Sync的lock方法上

}

Sync的lock方法是抽象的,实际的lock会代理到FairSync或是NonFairSync上(根据用户的选择来决定,公平锁还是非公平锁)

lockInterruptibly()

public void lockInterruptibly() throws InterruptedException {

sync.acquireInterruptibly(1);//代理到sync的相应方法上,同lock方法的区别是此方法响应中断

}

此方法响应中断,当线程在阻塞中的时候,若被中断,会抛出InterruptedException异常

tryLock()

public boolean tryLock() {

return sync.nonfairTryAcquire(1);//代理到sync的相应方法上

}

tryLock,尝试获取锁,成功则直接返回true,不成功也不耽搁时间,立即返回false。

unlock()

public void unlock() {

sync.release(1);//释放锁

}

释放锁,调用sync的release方法,其实是AQS的release逻辑。

newCondition()

获取一个conditon,ReentrantLock支持多个Condition

public Condition newCondition() {

return sync.newCondition();

}

其他方法就不再赘述了,若想继续了解可去API中查看。

小结

其实从上面这写方法的介绍,我们都能大概梳理出ReentrantLock的处理逻辑,其内部定义了三个重要的静态内部类,Sync,NonFairSync,FairSync。Sync作为ReentrantLock中公用的同步组件,继承了AQS(要利用AQS复杂的顶层逻辑嘛,线程排队,阻塞,唤醒等等);NonFairSync和FairSync则都继承Sync,调用Sync的公用逻辑,然后再在各自内部完成自己特定的逻辑(公平或非公平)。

接下来,关于如何实现重入性,如何实现公平性,就得去看这几个静态内部类了

NonFairSync(非公平可重入锁)

static final class NonfairSync extends Sync {//继承Sync

private static final long serialVersionUID = 7316153563782823691L;

/** 获取锁 */

final void lock() {

if (compareAndSetState(0, 1))//CAS设置state状态,若原值是0,将其置为1

setExclusiveOwnerThread(Thread.currentThread());//将当前线程标记为已持有锁

else

acquire(1);//若设置失败,调用AQS的acquire方法,acquire又会调用我们下面重写的tryAcquire方法。这里说的调用失败有两种情况:1当前没有线程获取到资源,state为0,但是将state由0设置为1的时候,其他线程抢占资源,将state修改了,导致了CAS失败;2 state原本就不为0,也就是已经有线程获取到资源了,有可能是别的线程获取到资源,也有可能是当前线程获取的,这时线程又重复去获取,所以去tryAcquire中的nonfairTryAcquire我们应该就能看到可重入的实现逻辑了。

}

protected final boolean tryAcquire(int acquires) {

return nonfairTryAcquire(acquires);//调用Sync中的方法

}

}

nonfairTryAcquire()

final boolean nonfairTryAcquire(int acquires) {

final Thread current = Thread.currentThread();//获取当前线程

int c = getState();//获取当前state值

if (c == 0) {//若state为0,意味着没有线程获取到资源,CAS将state设置为1,并将当前线程标记我获取到排他锁的线程,返回true

if (compareAndSetState(0, acquires)) {

setExclusiveOwnerThread(current);

return true;

}

}

else if (current == getExclusiveOwnerThread()) {//若state不为0,但是持有锁的线程是当前线程

int nextc = c + acquires;//state累加1

if (nextc < 0) // int类型溢出了

throw new Error(“Maximum lock count exceeded”);

setState(nextc);//设置state,此时state大于1,代表着一个线程多次获锁,state的值即是线程重入的次数

return true;//返回true,获取锁成功

}

return false;//获取锁失败了

}

简单总结下流程:

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

下图是我进阶学习所积累的历年腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节

以上【历年大厂高级工程师面试题集】、【Android高级进阶教学视频】、【Android高级知识点学习PDF】皆无偿分享给大家。如有需要,点击**【Android架构视频+BATJ面试专题PDF+学习笔记】**即可免费获取。

享给大家。如有需要,点击**【Android架构视频+BATJ面试专题PDF+学习笔记】**即可免费获取。

整理不易,望各位看官老爷点个关注转发,谢谢!祝大家都能得到自己心仪工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值