Sync是ReentrantLock的一个内部抽象类,它继承了AQS,而ReentrantLock另外两个内部类:FairSync和NonFairSync则同时继承了Sync,并实现了Sync的lock方法,类图如下
由类图可知要想理解ReentrantLock就需要理解AbstractQueuedSynchronizer(AQS)它实现了一个FIFO的队列,底层数据的数据结构是一个双向链表。
AQS中的重要属性
private transient volatile Node head;//头结点
/**
* Tail of the wait queue, lazily initialized. Modified only via
* method enq to add new wait node.
*/
private transient volatile Node tail; //尾节点
/**
* The synchronization state.
*/
private volatile int state; //资源
/**
* The current owner of exclusive mode synchronization.
*/
private transient Thread exclusiveOwnerThread; //记录当前持有排它锁的线程
当第一个线程进行抢锁时没有竞争修改state标识成功代码获取锁并将exclusiveOwnerThread属性改为当前线程。
final void lock() {
if (compareAndSetState(0, 1)) //当第一个线程抢锁时 修改资源state字段 成功改为1表示获得锁
setExclusiveOwnerThread(Thread.currentThread()); //将持有锁的线程exclusiveOwnerThread字段修改为当前成功获取锁的线程
else
acquire(1); //当有已经有线程获取锁时 其他线程进入抢锁进入此方法
}
public final void acquire(int arg) {
if (!tryAcquire(arg) && //再次尝试拿锁/判断当前线程是否重入
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //addWaiter(Node.EXCLUSIVE), arg) Node.EXCLUSIVE表示独占锁
selfInterrupt();
}
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; //当等待线程首次执行时 tail为空
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node); //组件等待线程的链表结构
return node;
}
private Node enq(final Node node) { //node当前线程节点
for (;;) {
Node t = tail; //第一次为空
if (t == null) { // Must initialize
if (compareAndSetHead(new Node())) //将head设置为一个哨兵节点
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) { //将尾指针指向当前线程节点
t.next = node;
return t;
}
}
}
}
经过循环会得到如下链表结构
回到上面的acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 的 acquireQueued方法
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor(); //获取当前线程节点的上一个节点(从上图可知就是head节点也即哨兵节点)
if (p == head && tryAcquire(arg)) { //再次尝试获取锁
setHead(node); //获取锁成功 将当前线程节点改为head节点并将当前线程的thread置为空
p.next = null; // help GC 将原来head节点的next置为空
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) //将当前线程挂起
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
进入shouldParkAfterFailedAcquire(p, node)方法中。
/**
* Checks and updates status for a node that failed to acquire.
* Returns true if thread should block. This is the main signal
* control in all acquire loops. Requires that pred == node.prev.
*
* @param pred node's predecessor holding status
* @param node the node
* @return {@code true} if thread should block
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* 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.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
waitStatus的默认值为0,所以这里的判断肯定是进入到else中,使用cas将waitStatus的值改变成Node.SIGNAL也就是-1。
for循环 shouldParkAfterFailedAcquire(p, node)方法后已经将waitStatus的值改编成-1了,所以最终会返回true,也就是执行 parkAndCheckInterrupt() 方法 将当前线程挂起。
调用unlock
unlock会调用release(int arg) 方法
public final boolean release(int arg) {
if (tryRelease(arg)) { //设置当前排它锁的线程为null,并将state设置为0 并返回true (如果重入则只会将state减一)
Node h = head;
if (h != null && h.waitStatus != 0) //挂起时已经将非tail指向的所有节点的waitStatus 置为-1 即此判断返回true
unparkSuccessor(h);
return true;
}
return false;
}
调用unparkSuccessor(h)方法
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)
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;
}
if (s != null)
LockSupport.unpark(s.thread);
}
Node s获取到node.next 也就是获取头结点后一个线程节点。因为waitStatus的默认值是0并且如果后面还有节点waitStatus的值也是-1所以当前if判断为false不会执行,继续执行到LockSupport.unpark(s.thread)唤醒线程,unlock方法执行结束。回到线程挂起
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
处线程继续执行,因为park过程中是可以被interrupt的,但是我们并没有去打断,所以我们返回是一个false。又回到死循环尝试获取到锁的方法中,因为是非公平锁中,当线程unlock释放锁后,通过tryAcquire()方法cas的方式来竞争获取锁。
获取成功将当前节点设置为头节点。
总结: