从另一个角度理解AQS

在初次学习AQS的时候,大部分人的解释大概都是这样的:

AQS(AbstractQueuedSynchronizer),中文直译过来就是抽象队列同步器,它内部维护一个用volatile关键字修饰的state变量,和一个FIFO双向队列,其中state表示同步状态,即>0表示锁已被抢占,反之表示锁可被抢占(基于最经典的ReentrantLock得出的片面结论,你可以自己去定义state的值的含义)而队列则是来完成资源获取线程的排队工作。

AQS是一个使用模版模式来定义的抽象类,其中有5个指定的方法,3个来访问或者修改state的方法,和9个模版方法以及5个重写过的方法。

而模版模式的主要原理就是,我觉得某一部分需要实现者来定义具体的运行过程,最后我再来调用实现者的代码,从而达到定制化的运行效果。

所以很多人会说AQS是同步基础,这句话说得很模糊,但如果我说它是实现一个锁的基础,那就很好理解了。

在理解AQS之前,我们可以先来看看synchronize的底层原理,但是我这里并不会讲它有什么作用,怎么用,不会可以问ai。

1.率先了解synchronized

我想说说java是如何实现synchronized:

synchronized底层使用monitor来实现,而monitor可以看作是一个工具,其内部是这样的:

其中最应该注意的是三个变量:owner,waitSet和EntryList,owner表示拥有该monitor的线程,如果没有,则表示锁可被抢占。而waitSet就是大家常说的等待池,EntrySet就是传说中的锁池。意思就是当线程没有抢到锁就会进入EntrySet锁池,而被调用wait()方法放弃锁而等待的时候会进入等待池。

这里重点说一下:这也是为什么wait()和notify()方法为什么会被放在Object类中而不是Thread类中,因为synchronized更多的时候与对象锁息息相关,放到Object里面就可以很轻易地分清楚,你在哪个对象锁的等待池,或者你要唤醒哪个对象等待池里的线程。

当然了,这也是为什么wait()方法必须要配合锁来使用,因为调用了这个方法之后,线程会释放锁去等待,你都没有锁的话,你释放什么?

2.AQS到底是什么?

说到这里,AQS的东西应该可以讲得很清楚了,AQS中的FIFO同步队列其实对应了synchronized中的锁池,意思就是你的线程没抢到锁之后,会被放入它维护的FIFO队列中,它的底层使用cas去设置state的状态,并且封装了硬件层面上加锁解锁的操作。

AQS是给其他人去实现一个完整的锁的其中一部分,而这个部分等同于锁池+加锁解锁的操作。所以AQS是面向锁的实现者的。

3.Lock与Condition

说完了AQS,再来说说Lock与condition。

Lock其实只是一个接口,它定义了加锁和解锁的抽象方法,但是并没有去实现,但如果你翻看过Lock的源码,你一定见过它把Condition类写在了内部,而且在它的实现类conditionObject,condition也维护了一个拥有头指针和尾指针的队列。

很多人说Condition叫做有条件等待队列,这句话非常地抽象,但如果我说它本质上跟sychronized中的等待池性质差不多时,你可能也就恍然大悟了。

这也就是为什么,需要先创建lock你才能创建Condition了。Condition中提供了类似于wait()和notify()一样的方法,就是await()和signal()。当你调用await()时,线程的状态也跟wait()差不多,放弃锁并且等待其他线程唤醒,这也就是为什么放到Lock中的原因。

4.Reentantlock作为锁实现的模版

说完了上面的三样“工具”,Reentantlock为想要自己去实现锁逻辑的开发者提供了一些思路,但是阅读源码的时候不难发现,Reentantlock继承了lock接口之后,在加锁和解锁代码中直接调用实现AQS的sync类中的实现代码。其实去深究为什么这么做,我个人觉得没有意义,因为感觉原因很简单,java语言中对规范的要求是比较显式的,AQS帮实现者们封装了底层实现,所以我们就可以在Lock接口的规范下,实现一个Lock锁了,重点就是区分synchronized锁。

说到这里,希望读者们对AQS,Lock 以及Condition能有一个大概的理解思路了,总体来说,它把实现一个完整锁的重要部分拆解成大家熟知的AQS,lock 和Condition,以便于实现者能够最大自由度地去实现定制化式的锁结构。

而对于AQS为什么会被称为同步机制的基础,我想原因已经找到了,就是它封装了底层对于加锁解锁的功能,使实现者能专注于锁结构的代码而不必过多操心底层技术细节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值