栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

ReentrankLock的底层原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

ReentrankLock的底层原理

底层是由AQS+CAS来实现的
无论是Semaphore还是ReetrantLock,其内部绝大多数方法都是间接调用AQS完成的。
当waitStrus为-1时状态为SIGNAL:表示线程已经准备好了,就等资源释放了



AQS的同步状态——State
ReentrantLock的基本实现可以概括为:先通过CAS尝试获取锁。如果此时已经有线程占据了锁,那就加入AQS队列并且被挂起。当锁被释放之后,排在CLH队列队首的线程会被唤醒,然后CAS再次尝试获取锁

加锁:

通过ReentrantLock的加锁方法Lock进行加锁操作。

会调用到内部类Sync的Lock方法,由于Sync#lock是抽象方法,根据ReentrantLock初始化选择的公平锁和非公平锁,执行相关内部类的Lock方法,本质上都会执行AQS的Acquire方法。

AQS的Acquire方法会执行tryAcquire方法,但是由于tryAcquire需要自定义同步器实现,因此执行了ReentrantLock中的tryAcquire方法,由于ReentrantLock是通过公平锁和非公平锁内部类实现的tryAcquire方法,因此会根据锁类型不同,执行不同的tryAcquire。(非公平锁tryAcquire的流程是:检查state字段,若为0,表示锁未被占用,那么尝试占用,若不为0,检查当前锁是否被自己占用,若被自己占用,则更新state字段,表示重入锁的次数。如果以上两点都没有成功,则获取锁失败,返回false。)

tryAcquire是获取锁逻辑,获取失败后,会执行框架AQS的后续逻辑,跟ReentrantLock自定义同步器无关。
如果获取锁失败,就会调用addWaiter加入到等待队列中去。
addWaiter方法,这个方法其实就是把对应的线程以Node的数据结构形式加入到双端队列里,返回的是一个包含该线程的Node。而这个Node会作为参数,进入到acquireQueued方法中。acquireQueued方法可以对排队中的线程进行“获锁”操作。
总的来说,一个线程获取锁失败了,被放入等待队列,acquireQueued会把放入队列中的线程不断去获取锁,直到获取成功或者不再需要获取(中断),失败后被挂起。线程入队后能够挂起的前提是,它的前驱节点的状态为SIGNAL

解锁:

通过ReentrantLock的解锁方法Unlock进行解锁。

Unlock会调用内部类Sync的Release方法,该方法继承于AQS。

Release中会调用tryRelease方法,tryRelease需要自定义同步器实现,tryRelease只在ReentrantLock中的Sync实现,因此可以看出,释放锁的过程,并不区分是否为公平锁。

释放成功后,所有处理由AQS框架完成,与自定义同步器无关。

公平锁和非公平锁不同之处在于,公平锁在获取锁的时候,不会先去检查state状态,而是直接执行aqcuire,而非公平锁当活跃的线程为等待队列线程被唤醒时则会直接检查state状态,若为0则直接获取.这里就体现了非公平.
0.每一个ReentrantLock自身维护一个AQS队列记录申请锁的线程信息;
1.通过大量CAS保证多个线程竞争锁的时候的并发安全;
2.可重入的功能是通过维护state变量来记录重入次数实现的。
3.公平锁需要维护队列,通过AQS队列的先后顺序获取锁,缺点是会造成大量线程上下文切换;
4.非公平锁可以直接抢占,所以效率更高;

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/770531.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号