大家好,这里是 淇妙小屋 ,一个分享技术,分享生存的博主
以下是我的主页,各个主页同步更新优质博客,创作不易,还请大家点波关注
掘金主页
后续会公布更多 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)