ReentrantLock存在两种实现的方式,公平锁
以及非公平锁
.默认为非公平锁。
ReentrantLock是依赖于java.util.concurrent.locks.AbstractQueuedSynchronizer
实现的
公平锁
获取锁过程
情景一:只有一个线程尝试获取锁(不存在竞争)
java.util.concurrent.locks.ReentrantLock#lock
-> java.util.concurrent.locks.ReentrantLock.FairSync#lock
----> java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire
在java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire
中就会出现逻辑判断处理了。具体代码如下
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
首先第一个tryAcuire()
方法为AQS中的抽象方法,对应公平锁的实现java.util.concurrent.locks.ReentrantLock.FairSync#tryAcquire
:
protected final boolean tryAcquire(int acquires) {
// 获取当前请求所的线程
final Thread current = Thread.currentThread();
// 获取锁标识位
int c = getState();
if (c == 0) { // 如果为0 -> 表示锁当前为自由状态
if (!hasQueuedPredecessors() && // 首先判断自己需不需要排队 -> 公平性的体现
compareAndSetState(0, acquires)) { // 如果不需要排队 -> 尝试去获取锁(通过CAS)
setExclusiveOwnerThread(current); // 设置获取锁的线程为当前线程
return true;
}
}
else if (current == getExclusiveOwnerThread()) { // 如果锁状态标识位不为0(锁已被持有)
// 如果持有锁的线程为当前线程
// 则在锁的标识位上加1
// 可冲入锁的体现
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
java.util.concurrent.locks.AbstractQueuedSynchronizer#hasQueuedPredecessors
:
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
// AQS中维护了一个双向链表,也就是说队列的结构。
// 它定义了一个head-头结点,tail-尾结点。在初始化时都为null
// node(pre, next, thread)
//
// head[node(null)] <-> node1(t1) <-> node2(t2)[tail]
//
//
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t && // 判断head 和 tail是否相等。如果在AQS刚被初始化的时候 head == tail,都为null。在此时,AQS刚初始化 所以 t!=h -> false
((s = h.next) == null || s.thread != Thread.currentThread());
// 判断 head.next 即第二个节点是否为 null 或者
// 第二个节点中的线程是否为当前线程。
// 首先这里有一个结论 -> 队列中的首节点是不排队的(因为它没有保存任何线程)。
}
在hasQueuedPredecessors()
获取到结果为false后 即 当前线程不需要排队等待,然后会调用java.util.concurrent.locks.AbstractQueuedSynchronizer#compareAndSetState
方法进行CAS操作,如果成功则获取到锁则设置当前锁的持有线程为当前线程,此时我们己经假设当前只有它一个线程,所以至此它获取到了锁并返回true,此时tryAcquire返回true,acquire正常结束。
情景二:锁已经被持有
前几步的执行逻辑相同。需注意的是,此时hasQueuedPredecessors()
方法中的h != t依旧为 false
及此时Thread2
依旧不需要排队(当然,因为除它之外也没有别的线程)。然后Thread2
在执行java.util.concurrent.locks.AbstractQueuedSynchronizer#compareAndSetState
方式时由于Thread1
还未释放锁,所以此时他是失败的,即
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
中的tryAcquire(arg)
返回false
,此时if语句条件继续判断。
首先java.util.concurrent.locks.AbstractQueuedSynchronizer#addWaiter
方法
private Node addWaiter(Node mode) {
// 创建一个node,保存当前请求线程,以及所的持有模式 -> 独占
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
// 此时由于tail 还处在初始化状态,所以 pred = tail = null
Node pred = tail;
if (pred != null) { // false
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
java.util.concurrent.locks.AbstractQueuedSynchronizer#enq
方法:
private Node enq(final Node node) {
for (;;) { // 一个死循环
Node t = tail;
if (t == null) { // Must initialize。必须对队列进行初始化
if (compareAndSetHead(new Node()))
// 注意此时将头结点new 了一个Node
// 即 头结点中的 线程为null
tail = head;
// 继续进行下一次循环
} else {
node.prev = t;
// 将新增结点设置在尾部
if (compareAndSetTail(t, node)) {
t.next = node;
// 此时队列结构为
// [head]node0(thread=null) <->node1(thread=thread1)[tail]
return t;
}
}
}
}
然后执行java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireQueued
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// for 死循环
// 取出当前node及node1(thread=thread1)的结点
// p = node0(thread=null)
final Node p = node.predecessor();
// 此时p == head 为 true 然后尝试进行一个tryAcquire操作及会尝试获取锁
// 尝试获取锁的原因为:有可能在当前线程入队的时候锁已经被释放了。
if (p == head && tryAcquire(arg)) {
// 获取锁成功
// 将当前节点从队列中移除
// 但此处有个主意点,主意setHead方法
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 如果当前节点不为队列中的第二个节点 或者 尝试获取锁失败
if (shouldParkAfterFailedAcquire(p, node) && // 此时返回false -> 即又进行一次循环并尝试获取锁。
// park当前线程
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
java.util.concurrent.locks.AbstractQueuedSynchronizer#setHead
setHead方法会将当前node中的thread设置为null
所以至此可得出结论:队列中head节点中的node对象不保存任何Thread
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}
java.util.concurrent.locks.AbstractQueuedSynchronizer#shouldParkAfterFailedAcquire
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
// ws 为Node节点中保存的数据,注意此时的pred节点为刚才初始化队列是new出来的,
// 所以 waitStatus字段为初始默认值0
int ws = pred.waitStatus;
if (ws == Node.SIGNAL) // static final int SIGNAL = -1;
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
// 设置ws为-1
// 注意:此时设置的为当前节点的pred节点的ws为-1,然后返回false
// 当第二次进入此方法时,ws为-1,表示此时当前node可以park了。
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
释放锁
java.util.concurrent.locks.ReentrantLock#unlock
--> java.util.concurrent.locks.AbstractQueuedSynchronizer#release
public final boolean release(int arg) {
if (tryRelease(arg)) {
// 释放成功
Node h = head;
// 如果头结点不为null 并且 头结点的waitStatus不为0 -> unpark下一个排队的线程
// 思考:之前thread1将head中的ws设置为-1的时机
// 此时如果还未被设置为-1表示 thrad还未park。
// 应为thread1在设置它的pred结点的ws为-1之后还进行了一次自旋操作。如果获取到了锁,那么相应的队列结构也需要调整。也就不会进入park状态。如果thread1进入了park状态那么表示thread1的pred node中的ws必定为-1。依次类推 [head](node1(thread=null, ws=-1)) <-> node2(thread=thread2, ws=-1) <-> node3(thread=thread3, ws=-1)[tail]
//
if (h != null && h.waitStatus != 0)
// 如果head中的ws不为0时则表示队列中存在排队的线程 -> unpark
unparkSuccessor(h);
return true;
}
return false;
}
java.util.concurrent.locks.ReentrantLock.Sync#tryRelease
protected final boolean tryRelease(int releases) {
// 锁标识 - 1
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 为0 则锁没有没当前线程冲入,可以free
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
java.util.concurrent.locks.AbstractQueuedSynchronizer#unparkSuccessor
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
// -1 则设置为 0
// 所以aqs中是以前一个节点的ws是否为-1表示当前节点中的线程是否需要park的
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
// unpark当前节点的下一个节点中的线程
if (s != null)
LockSupport.unpark(s.thread);
}