Reentrantlock及可重入锁,读源码首先要看下它的outline:
其核心就是公平锁fairSync和非公平送NonFairSync
我们可以看到这两个锁有共同的方法:lock();
- fairSync
final void lock() {
acquire(1);
}
- NonfairSync
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
在资源没有被占用的情况下:
非公平锁是: 先state+1,然后直接得到锁,
而公平锁则是: 先尝试去获取锁,如果得到了锁则state+1.
如果是同一线程,再次申请锁
两种锁,表现基本一致,可以参考下面的代码块. (只是这段代码块在不同函数中)
fairSync:
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
NonfairSync
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
如果是不同线程申请锁:
从业务逻辑来看,公平锁和非公平锁唯一的区别就是需要判断当前线程是不是链表头.但是一直有一点不明白的,在c==0的情况下, 不是就可以说明已经是表头了吗? 为什么还要检查 isFirst(current). compareAndSetState(0, acquires) 也可以保证在并发的情况下只有state=0才能获取锁.
总结
非公平锁,和公平锁只有在state=0的时候,业务逻辑不一样.
在stage=0的时候,非公平锁是直接获取锁,没有维护等待队列.
在stage=0的时候, 公平锁依然需要检查当前线程是否是等待队列的第一个.