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.非公平锁可以直接抢占,所以效率更高;

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值