为什么要单独将这部分抽出来总结?
纵观JUC下基于AQS实现的工具类,其实现思想都很统一:
- state代表状态值
- 通过try*()方法尝试单次更改state,根据state当前情况决定是否进入do*()中
- 一旦进入了do*()中,就代表了可能加入同步/等待队列中进行阻塞等待
- 而当线程从阻塞苏醒后,又会通过try*()方法尝试单次更改state,并根据state当前情况决定是否设置自身为新的头节点或阻塞与否
因此锁的获取能否,关键还是看子类复写的try*()方法,AQS自身提供的其他的方法都是对获取成功或失败的辅助工作
本文单独将try*()提出来,下文将do*()提出来,从而更好的理解JUC的设计思想
暴露方法
// 尝试获取 独占锁
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
// 尝试释放 独占锁
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
//尝试获取 共享锁
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
//尝试释放 共享锁
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
//判断是否时当前线程在持有锁
protected boolean isHeldExclusively() {
throw new UnsupportedOperationException();
}
以上五个方法时AQS向外暴露的方法,子类只需要覆盖这几个方法即可注意着五个方法并不是抽象方法,因此子类并不是必须全部覆盖这些方法。JUC中实现这些方法的子类有
独占锁是仅能有一个线程持有锁,而共享锁是可以同时多个线程持有锁的,因此独占锁和共享锁的实现方式分开实现
除了以上的四种try*()
方法外,AQS自身实现了诸多的如acquire
和doAcquire()
等方法,他们之间的区别在于try*()
方法代表一次尝试性的获取锁操作,如果获取到了就拿到了锁,否则直接返回。而AQS自身实现的acquire
和doAcquire()
等方法如果获取不到锁会能够进入同步/等待队列中阻塞等待进行锁的争夺,直到拿到了锁返回。对于共享锁,try*()
也会进行自旋获取,因为共享锁可以被多个线程持有
AQS通过一个private volatile int state;
来表示锁的状态,当state=0时代表无锁,>0代表有锁,>1代表重入次数
AQS从AOS继承了private transient Thread exclusiveOwnerThread;
用来记录当前持有独占锁的线程
下面介绍不同子类的try*()
方法实现
不同的子类实现
ReentrantLock
ReentrantLock
实现了独占锁的尝试获取和尝试释放方法,因此我们从这里可以看出ReentrantLock
是一种独占锁
- 非公平锁:线程获取锁不会排队,谁拿到算谁的
protected final boolean tryAcquire(int acquires){
final Thread current = Thread.currentThread();
int c = getState();
// state==0代表当前没有锁,可以进行获取
if (c == 0) {
//CAS设置state为acquires,成功后标记exclusiveOwnerThread为当前线程
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//代表重入,满足条件直接进行state的增加,因为持有锁,所以不需要CAS
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;
}
// 调用该方法表明该线程是持有锁的,因此不需要CAS操作
protected final boolean tryRelease(int releases){
int c = getState(