1.非公平锁的加锁流程
reentrantLock默认构造是new一个非公平锁
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
- 加锁:调用的是同步器的lock
public void lock() {
sync.lock();
}
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
- NonfairSync继承自AQS
- 没有竞争时
- 第一个竞争出现时
- CAS尝试将state从0,改成1,失败
final void lock() {
if (compareAndSetState(0, 1))//失败
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);//进入acquire
}
- 进入tryAcquire逻辑,这时state已经是1,仍然失败
public final void acquire(int arg) {
if (!tryAcquire(arg) && //尝试加锁
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //等待,创建节点对象
selfInterrupt();
}
- 进入addWaiter逻辑,构造Node队列
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;
}
- 图中黄色三角表示该Node的waitStatus状态,0是默认正常状态
- Node是懒惰创建
- 其中第一个Node称为Dummy(哑元)或哨兵,用来占位,不关联线程
- 当前线程进入acquireQueued逻辑
/**
* Acquires in exclusive uninterruptible mode for thread already in
* queue. Used by condition wait methods as well as acquire.
*
* @param node the node
* @param arg the acquire argument
* @return {@code true} if interrupted while waiting
*/
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)) {//看第一个是不是head,是就是真正第一个节点,还有资格去尝试获取锁
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
- acquireQueued会在一个死循环中不断尝试获得锁,失败后进入park阻塞
- 如果是紧邻这head,那么tryAcquire尝试获得锁,当然state是1,会失败
- 进入shouldParkAfterFailedAcquire逻辑,将前驱node,即head的waitStatus改为-1,这次返回false。-1表示这个节点有责任唤醒它的后继节点
- shouldParkAfterFailedAcquire执行完毕回到acquireQueued,再次tryAcquire尝试回去锁,当然这时state 仍是1,失败
- 当再次进入shouldParkAfterFailedAcquire时,这时因为前驱node的waitStatus已经是-1,这次就返回true
- 进入parkAndCheckInterrupt
- 进入**parkAndCheckInterrupt,**阻塞住灰色表示
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
- 多个线程失败就是这样
2.解锁竞争成功流程
- Thread-0释放锁,进入tryRelease流程,如果成功
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)//不为空,不为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;
}
- 设置exclusiveOwnerThread为null
- state=0
- 当前队列不为null,且head的watiStatus=-1,进入unparkSuccessor流程,找到离head最近的node,unpark恢复运行,回到Thread-1的acquireQueued流程
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);
}
- 把当前节点设置为头节点,原来节点断开(acquireQueued逻辑中)
3.竞争锁失败流程
- 这时如果有其他线程来竞(非公平的体现)
- Thread-4被设置为exclusiveOwnerThread,sate=1
- Thread-1再次进入acquireQueued流程,获取锁失败,重新进入park阻塞