JAVA REENTRANTLOCKSEMAPHORE 的实现与 AQS 框架
Posted 张宏杰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA REENTRANTLOCKSEMAPHORE 的实现与 AQS 框架相关的知识,希望对你有一定的参考价值。
ReentrantLock是JDK提供的一个可重入互斥锁,所谓可重入就是同一个锁允许被已经获得该锁的线程重新获得。可重入锁的好处可以在递归算法中使用锁,不可重入锁则导致无法在递归算法中使用锁。因为第二次递归时由于第一次递归已经占有锁,而导致死锁。本文我们将探讨JDK中ReentrantLock的实现。
Semaphore是JDK提供的一个可共享的同步组建,有n个许可,多个线程可以共同去获得许可,当线程申请的许可小于n时即可成功申请,否则申请失败。
AQS(AbstractQueuedSynchronizer)是Java实现同步组建的基础框架,一般以静态内部类的形式实现在某个同步组件类中,通过代理的方式向外提供同步服务,ReentrantLock和Semaphore都是基于AQS实现的同步组件,前者是独占式同步组建,即一个线程获得后,其他线程无法获得。后者是共享式同步组件,一个线程获得后,在满足的条件下,其他线程也可以获得。
AQS工作原理
AQS是Java实现同步组建的基础框架,其基本思想是用一个volatile int state变量来表示当前同步组件的状态,用getState()获取同步组件的状态,用compareAndSet(int expect, int update)来对state状态进行操作,compareAndSet可以保证对state变量更新值的原子性。AQS中很多方法是final的,即不允许用户覆盖,用户自定义的方法一般有:
- tryAcquire: 独占式获取同步状态,该函数一般首先查询state的值,如果state不允许继续被获取,直接返回false。如果state允许继续被获取,CAS尝试更新state的值,成功返回true,失败返回false
- tryAcquireShared:共享式的获取同步状态,该一般是在CAS死循环获取state的值,计算state被获取后的值,如果该值为负数,直接返回负数表示失败,如果该值为正值,则用CAS更新该值,当CAS更新失败时,重复上述步骤,直至返回负数或CAS更新成功返回正值。
- tryRelease:独占式的释放同步状态
- tryReleaseShared:共享式的释放同步状态,一般在CAS死循环中反复尝试,直至释放成功
- isHeldExclusively:判断当前同步器是否被当前线程占有
AQS提供的模板方法有:
- acquire:独占式的获取同步状态,获取成功则返回,获取失败则会进入等待队列,该方法会调用用户自定义的tryAcquire函数
- acquireInterruptibly:与acquire类似,不同在于当进入等待队列时,遇到中断会抛出InterruptedException异常,用户可以处理该中断异常
- tryAcquireNanos:在acquireInterruptibly的基础上增加了时间限制,一定时间内没有成功获取则返回false
- acquireShared:共享式的获取同步状态,成功则返回,失败则进入等待队列,该方法会调用用户自定义的tryAcquired函数
- acquireSharedInterruptibly:在等待队列可以相应中断,与上类似
- tryAcquireShared:在acquireSharedInterruptibly增加了超时限制
- release:独占式的释放同步状态,会调用用户自定义tryRelease函数
- releaseShared:共享式的释放同步状态,会调用用户自定义tryReleaseShared函数
- getQueuedThreads:获取等待队列线程集合
ReentrantLock源码分析
ReentrantLock的默认构造函数是
1 2 3 |
public
ReentrantLock()
sync =
new
NonfairSync();
|
NonfairSync继承了Sync,Sync是一个抽象类,并继承了抽象类AbstractQueuedSynchronizer。
ReentrantLock是一个独占式的锁,所以它需要实现tryAcquire函数和tryRelease函数
tryAcquire函数源码如下
1 2 3 |
protected
final
boolean
tryAcquire(
int
acquires)
return
nonfairTryAcquire(acquires);
|
nonfairTryAcquire(acquires)源码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
final
boolean
nonfairTryAcquire(
int
acquires)
final
Thread current = Thread.currentThread();
int
c = getState();
if
(c ==
0
)
if
(compareAndSetState(
0
, acquires))
setExclusiveOwnerThread(current);
return
true
;
else
if
(current == getExclusiveOwnerThread())
int
nextc = c + acquires;
if
(nextc <
0
)
// overflow
throw
new
Error(
"Maximum lock count exceeded"
);
setState(nextc);
return
true
;
return
false
;
|
- 先得到当前线程