Java并发编程之一张图理解ReentrantLock
作者:互联网
一张图理解ReentrantLock
首先看图。
1.lock()跟踪源码
这里对公平锁和非公平锁做了不同实现,由构造方法参数决定是否公平。
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
1.1.非公平锁实现
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
代码量很少。首先compareAndSetState(0, 1)
通过CAS(期望值0,新值1,内存值stateOffset)
- 如果修改成功,即抢占到锁,
setExclusiveOwnerThread(Thread.currentThread());
将AQS中的变量exclusiveOwnerThread
设置为当前抢占到锁的线程,也就是图中的ThreadA。 - 若没有抢占成功,证明此时锁被占用,执行方法
acquire(1);
。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
这里主要看两个方法tryAcquire(arg)
和acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
。当满足if条件后,会给当前线程标记一个interrupt
状态。
1.1.1.tryAcquire(arg)
这个方法又有多个实现。这里看NonfairSync
非公平锁。
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
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;
}
在这个方法中,还不死心,首先会判断下AQS中的state是否为0,为0也就是说距离上次尝试获取锁到现在准备进入队列(双向链表)中这段时间内,锁已经被释放,可以重新CAS尝试获取锁。
如果当前锁还是被持有状态,就是state!=0
,就会判断,当前线程是不是当前持有锁的线程exclusiveOwnerThread
,如果是,则state+1
,从这里可以看出state表示的是重入次数。
全部不满足,返回false。
1.1.2.acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
tryAcquire(arg)返回false,证明当前线程还是没有获取到锁。那么就要进入队列等待了,首先addWaiter
方法,将当前线程封装成一个Node,如果pred不为空,则将当前节点做链表的尾部插入,同时为了防止在此期间前序节点已经不在队列中了,也会运用CAS操作来执行(期望值pred,新值node,内存值tailOffset)。
如果前序节点为空,或者在CAS时发现前序节点已经不存在了,则重新构建链表,将当前节点封装的Node,加入到链表当中。
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
到这里,基于非公平锁的实现结束。
1.2.公平锁实现
公平锁和乐观锁的区别就在于,非公平锁acquire(1)
前会先尝试获取锁,公平锁
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
}
1.2.1.tryAcquire(arg)
在tryAcquire中也和非公平锁有一定的区别。在当前锁没有被占有时。非公平锁不用考虑目前AQS队列中的排队情况,直接通过CAS尝试获取锁。公平锁会看目前队列的状态,再来决定是尝试占有锁还是在队列中等待。
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;
}
未完待续…
标签:Node,node,编程,Java,ReentrantLock,tryAcquire,arg,return,final 来源: https://blog.csdn.net/weixin_44692700/article/details/117173011