大家好,这里是淇妙小屋,一个分享技术,分享生活的博主
以下是我的主页,各个主页同步更新优质博客,创作不易,还请大家点波关注
掘金主页
后续会发布更多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)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。