模拟多线程加锁情景 ReentrantLock 默认是非公平锁
ReentrantLock lock = new ReentrantLock();
线程1 lock.lock();
执行compareAndSetState(0, 1),此时state=0,所以CAS成功,state=1,并将当前占有线程设为线程1
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
此时 线程2 也 lock.lock();
执行compareAndSetState(0, 1) 发现state=1了,不为0,所以CAS失败,走acquire(1)方法。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
因为是非公平锁,还会去尝试加锁,但此时线程1正独占着锁,加锁失败。走acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法,先看addWaiter(Node.EXCLUSIVE)
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;
}
先创建了当前线程2的一个Node对象,此时tail指针为空,pred指针指向tail也为空,走enq(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;
}
}
}
}
看到了一个无限for循环。。 t指针指向tail都为空,走 compareAndSetHead(new Node()),创建一个空的Node结点并将Head指针指向空Node,把tail指针也指向空Node。然后进入下一次循环,t指针指向tail,即t指针也指向空Node,t!=null,线程2Node的prev指针指向空Node,tail指针指向线程2Node,空Node的next指针指向线程2Node,返回 空Node。此时形成了空Node和线程2Node的双向链表结构
下面再来看acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
又是个无限for循环。。p指针指向线程2Node前面那个空Node结点,p==head为true,此时又将尝试加锁,加锁失败后走shouldParkAfterFailedAcquire(p, node) 方法
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
空Node的waitStatus=0,ws=0,走compareAndSetWaitStatus(pred, ws, Node.SIGNAL)方法,就是把空Node结点的waitStatus设为SIGNAL,并返回false。进入下一次for循环,再次进入这个方法,此时ws == Node.SIGNAL成立,返回true。执行parkAndCheckInterrupt()方法
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
意思就是把当前线程2挂起,阻塞等待。线程2的lock过程就卡在 LockSupport.park(this);这一步上了。
下面我们来看线程1释放锁会发生什么:
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
走到tryRelease(1) c=1-1=0,线程1就是当前占有线程,执行 setExclusiveOwnerThread(null);将当前占有线程设为null,setState(0),return true。
接着走这里的代码
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
h指针指向head,即指向空Node,空Node的waitStatus=SIGNAL,不为0,走unparkSuccessor(h);
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
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);
}
compareAndSetWaitStatus(node, ws, 0);将空Node的waitStatus设为0,s指针指向线程2Node,执行 LockSupport.unpark(s.thread); 将线程2唤醒
这里线程1释放锁过程结束。就是将当前占有线程设null,设state=0,并将队头线程2唤醒
此时线程2
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
返回 false
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
线程2将去尝试获取锁了,如果获取成功
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}
将head指针指向线程2Node,并将Node设为空,将原空Node去掉
就先说到这吧。。