大家好,这里是淇妙小屋,一个分享技术,分享生存的博主
以下是我的主页,各个主页同步更新优质博客,创作不易,还请大家点波关注
掘金主页
后续会公布更多MySQL,Redis,并发,JVM,分布式等面试热点常识,以及Java学习路线,面试重点,职业规划,面经等相干博客
转载请表明出处!
本文将通过ReentrantLock和Semaphore带你看看AQS的独占模式和共享模式是怎么实现的
- ReentrantLock实现了AQS的独占模式
- Semaphore实现了AQS的共享模式
1. ReentrantLock介绍
可重入:任意线程取得锁后可能再次获取该锁而不会被锁阻塞
ReentrantLock实现了AQS的独占模式,是一个可重入锁,还分为 偏心锁与 非偏心锁
- 偏心锁:先对锁进行获取申请的线程肯定先取得锁
- 非偏心锁
非偏心锁的效率高于偏心锁
非偏心锁可能呈现 线程饥饿问题——局部线程迟迟无奈取得资源
ReentrantLock大多数办法的实现都是Sync及其子类来实现,ReentrantLock只是对外裸露了接口
2. ReentrantLock取得锁
2.1 非偏心锁
2.2 偏心锁
2.3 偏心锁与非偏心锁的不同
FairSync和NonfairSync的 lock() 和 tryAcquire() 逻辑不同
- 非偏心锁在lock()办法的开始就会尝试去通过CAS批改同步状态以取得锁,偏心锁不会
在自旋时,非偏心锁和偏心锁都会在前继节点为同步队列首节点时,调用tryAcquire()尝试获取锁
在 tryAcquire()中,如果state为0,那么非偏心锁不会关怀节点在同步队列中的地位,间接尝试CAS批改state取得锁;然而非偏心锁关怀节点的地位,会查看是否有前继节点,如果有,就会放弃
上述2点保障了偏心锁肯定是——先对锁进行获取申请的线程肯定先取得锁,而非偏心锁不肯定
3. ReentrantLock开释锁
偏心锁开释锁与非偏心锁开释锁采纳同一个逻辑
4. Semaphore介绍
Semaphore实现了AQS的共享模式
信号量,用来管制同时拜访特定资源的线程数目
初始化时指定信号量(permits)的数目(实质还是AQS的state)
如果线程想要拜访一个资源,必须先取得信号量缩小,信号量为0时,线程无法访问资源,只能WATING期待信号量>0,
如果应用完资源,开释后,会补充信号量
(之前的ReentrantLock中state=0示意锁可用,state不为0示意锁不可用,Semaphore这里state不为0示意锁可用,state为0示意锁不可用)
5. Semaphore办法介绍
//尝试获取一个信号量,如果信号量不为0,那么将信号量-1,返回//如果信号量为0,WAITING直到信号量不为0//可中断public void acquire() throws InterruptedException//尝试获取多个信号量,如果信号量足够,那么将信号量-permits,返回//如果信号量不够,WAITING直到信号量不为0//可中断 public void acquire(int permits) throws InterruptedException //同acquire(),但不可中断public void acquireUninterruptibly() //同acquire(int permits),但不可中断public void acquireUninterruptibly(int permits)//开释一个信号量public void release() //开释permits个信号量public void release(int permits)
6. 办法详解
6.1 void acquire(int permits)
底层调用的还是AQS共享模式获取锁的那一套
偏心模式——FariSync中的 tryAcquireShared(int acquires)
.png)
非偏心模式——NonfairSync中的 tryAcquireShared(int acquires)调用Sync中的 nonfairTryAcquireShared(int acquires)
6.2 void release(int requires)
底层调用的还是AQS共享模式开释锁的那一套
Sync实现了 tryReleaseShared(int releases)