reentrantlock公平锁与非公平锁对比
作者:互联网
先说结论:非公平锁加锁时先参与锁竞争,如果state为0,则获取到锁。如果不为0,分三种情况。第一种情况,state为0(距离刚刚判断已经过去一会儿了,刚刚不为零,现在可能为零),获取到锁。第二种情况,state不为0,但是持有锁的线程是自己,也就是二次加锁,此时state会加一。第三种情况,state不为0并且持有锁的线程也不是自身,则将当前线程加入到一个双向链表队列中。
公平锁加锁时,分三种情况。第一如果state为0,判断队列中是否有线程比自己先来,如果有,则将自己加入队尾,如果没有则获取到锁。第二种情况,state不为0,但是如果当前持有锁的线程是自己,就进行二次加锁。第三种情况,state不为0并且持有锁的线程也不是自身,则将当前线程加入到队尾。
下面来看一下,源码实现
非公平锁:
final void lock() {
//先参与锁竞争
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//竞争失败在执行acquire方法
acquire(1);
}
//这里分为三种情况
1.state为0
2.当前线程持有锁
3.加入阻塞队列队尾。
前两种情况在tryAcquire中实现,第三种情况在acquireQueued中实现
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
公平锁:
//公平锁相对于非公平锁少了一次锁竞争
final void lock() {
acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
同样分三种情况时,state为0,两种锁的处理方法也不同,开头我们总结的时候用文字描述了,下面我们从代码的层面描述一下。
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//非公平锁state为0时,直接cas获取锁
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;
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//公平锁state为0时,判断队头线程是否比当前线程等待时间长
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;
}
标签:return,nextc,int,reentrantlock,state,线程,公平,与非,final 来源: https://blog.csdn.net/sheng_xinjun/article/details/120314350