其他
大家好,我是阿星,今天是一篇硬核文,请各位读者大大们系好安全带,马上要发车了。晕车的朋友,可以先吃一颗阿星独家秘制的晕车药,童叟无欺,货真价实,还免费,白嫖党狂喜(16张图揭开AQS)。本文大纲如下纵观全局我的英文名叫ReentrantReadWriteLock(后面简称RRW),大家喜欢叫我读写锁,因为我常年混迹在读多写少的场景。读写锁规范作为合格的读写锁,先要有读锁与写锁才行。所以声明了ReadWriteLock接口,作为读写锁的基本规范。之后都是围绕着规范去实现读锁与写锁。读锁与写锁WriteLock与ReadLock就是读锁和写锁,它们是RRW实现ReadWriteLock接口的产物。但读锁、写锁也要遵守锁操作的基本规范。所以WriteLock与ReadLock都实现了Lock接口。那么WriteLock与ReadLock对Lock接口具体是如何实现的呢?自然是少不了我们的老朋友AQS了。AQS众所周知,要实现锁的基本操作,必须要仰仗AQS老大哥了。AQS(AbstractQueuedSynchronizer)抽象类定义了一套多线程访问共享资源的同步模板,解决了实现同步器时涉及的大量细节问题,能够极大地减少实现工作,用大白话来说,AQS为加锁和解锁过程提供了统一的模板函数,只有少量细节由子类自己决定。AQS简化流程图如下如果读者想深入AQS细节,可以看阿星的这篇文章:16张图揭开AQSSyncAQS为加锁和解锁过程提供了统一的模板函数,只有少量细节由子类自己决定,但是WriteLock与ReadLock没有直接去继承AQS。因为WriteLock与ReadLock觉得,自己还要去继承AQS实现一些两者可以公用的抽象函数,不仅麻烦,还有重复劳动。所以干脆单独提供一个对锁操作的类,由WriteLock与ReadLock持有使用,这个类叫Sync。Sync继承AQS实现了如下的核心抽象函数tryAcquirereleasetryAcquireSharedtryReleaseShared其中tryAcquire、release是为WriteLock写锁准备的。tryAcquireShared、tryReleaseShared是为ReadLock读锁准备的,这里阿星后面会说。上面说了Sync实现了一些AQS的核心抽象函数,但是Sync本身也有一些重要的内容,看看下面这段代码我们都知道AQS中维护了一个state状态变量,正常来说,维护读锁与写锁状态需要两个变量,但是为了节约资源,使用高低位切割实现state状态变量维护两种状态,即高16位表示读状态,低16位表示写状态。关于读写锁状态设计具体细节可以看阿星的文章:ReentrantReadWriteLock的位运算Sync中还定义了HoldCounter与ThreadLocalHoldCounterHoldCounter是用来记录读锁重入数的对象ThreadLocalHoldCounter是ThreadLocal变量,用来存放第一个获取读锁线程外的其他线程的读锁重入数对象如果读者对ThreadLocal不太熟悉,可以去看阿星的文章: