一、ReentrantLock 公平锁加锁流程
-
首先,根据我们传入的boolean值决定ReentrantLock为公平锁还是非公平锁。(默认为非公平锁)
-
我们调用lock()方法加锁时,底层实际为调用ReentrantLock持有的Sync对象的acquire(1)方法。
public void lock() { sync.acquire(1); }
-
acquire(1)方法调用tryAcquire(1)方法尝试加锁,失败后调用acquiredQueued(addWaiter(Node.EXECUSIVE),arg)方法将当前线程包装成一个Node节点加入到等待队列
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
-
tryAcquire()方法会首先判断锁是否空闲,如果空闲则用hasQueuePreProcessor()判断自己是否需要排队,如果不需要排队则CAS操作尝试获取锁,获取锁成功,则将持有锁的线程设置为自己。如果需要排队,则返回false,表示用tryAcquire(1)方法尝试获取锁失败,将自己加入到等待队列。
@ReservedStackAccess protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); //锁空闲 if (c == 0) { //判断自己是否需要排队 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { //不需要排队则用CAS获取锁 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;//否则,返回尝试加锁失败 }
-
如果tryAcquire(1)判断锁非空闲,则看是否为自己持有锁,若为自己持有,则重入。否则返回false,表示尝试获取锁失败,将自己加入到等待队列。(该方法分公平锁实现和非公平锁两种实现)
//判断自己是否需要排队 public final boolean hasQueuedPredecessors() { Node h, s; //如果等待队列的head不为空 if ((h = head) != null) { if ((s = h.next) == null || s.waitStatus > 0) { s = null; // traverse in case of concurrent cancellation for (Node p = tail; p != h && p != null; p = p.prev) { if (p.waitStatus <= 0) s = p; } } //判断是否有等待着的线程且不是自己 if (s != null && s.thread != Thread.currentThread()) return true; } //如果head为null,则不需要等待,因为没有等待队列 return false; }
-
acquiredQueued(addWaiter(Node.EXECUSIVE),arg)会首先执行addWaiter()方法,该方法比较简单。
private Node addWaiter(Node mode) { Node node = new Node(mode); //大体逻辑就是判断等待队列是否为空,如果是空,则初始化之后再将自己插入,否则直接将自己插入队尾 for (;;) { Node oldTail = tail; if (oldTail != null) { node.setPrevRelaxed(oldTail); if (compareAndSetTail(oldTail, node)) { oldTail.next = node; return node; } } else { initializeSyncQueue(); } } }
-
然后再执行acquireQueued方法。首先判读自己是否是head的.next节点,如果是则tryAcquire(1)再次尝试获取锁,如果不是调用park()让自己睡眠。
final boolean acquireQueued(final Node node, int arg) { boolean interrupted = false; try { for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC return interrupted; } if (shouldParkAfterFailedAcquire(p, node)) //此处会多自旋一次 //因为每个Node节点的waitStatus是系统默认值0,会返回false,自旋一次 //即每一次当前节点会把前一个节点的状态改为-1,即SIGNAL状态 //为啥不自己改自己呢?因为自己无法更改,如果在park前设置,但无法保证原子性 interrupted |= parkAndCheckInterrupt(); } } catch (Throwable t) { cancelAcquire(node); if (interrupted) selfInterrupt(); throw t; } }
二、非公平锁加锁流程
非公平锁和公平锁加锁过程最大的不同是tryAcquire(1)方法,非公平锁该方法的实现是调用了nonfairTryAcquire(acquires)。
即lock()—>Sync.acquire(1)---->tryAcquire(1)---->nonfairTryAcquire(acquires)。
@ReservedStackAccess
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//非公平锁只要判断锁是空闲的,则直接尝试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;
}
非公平锁如果用tryAcquire(1)获取锁失败,则后面的流程和公平锁一样。
三、流程图