非公平锁的上锁过程
2020-03-19 本文已影响0人
kele2018
1、lock
final void lock() {
//一进来就可以尝试获取锁 不用管自己前面是否已经有人在排队
if (compareAndSetState(0, 1))
//拿到锁且可以用 就在锁上标记一下 哪个线程在用这把锁
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
2、acquire
public final void acquire(int arg) {
/**
* tryAcquire(arg)这个方法是留给子类覆盖的 给我们一个自定义获取锁逻辑的机会
* addWaiter(Node.EXCLUSIVE)这个方法会把当前线程封装成一个Node对象,然后添加到链表(双向)中
*/
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)){
selfInterrupt();
}
}
2.1、tryAcquire
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//再一次尝试获取锁
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
} else if (current == getExclusiveOwnerThread()) { //ReentranLock为可重入锁
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
2.2、addWaiter
private Node addWaiter(Node mode) {
//把当前没有获取锁的线程封装成一个node对象
Node node = new Node(Thread.currentThread(), mode);
//拿到尾部节点
Node pred = tail;
if (pred != null) {
//当前节点的prev指向尾部节点
node.prev = pred;
//设置尾部节点为当前节点
if (compareAndSetTail(pred, node)) {
//设置原先尾部节点的next为当前节点
pred.next = node;
return node;
}
}
enq(node);
return node;
}
2.2.1、 enq
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) {
/**
* 初始化head节点和tail节点,让它们都指向一个空节点
* 这就相当于把第一个位置空出来,以后哪个线程坐在这个位置上哪个线程就工作,而有资格获取锁的线程永远是排在第一个位置后的线程
*/
if (compareAndSetHead(new Node())){
tail = head;
}
} else {
/**
* 这里就是快速入链表的过程,完成三件事
* 1、尾部节点指向当前节点
* 2、原先的尾部节点的next节点指向当前节点
* 3、当前节点的prev节点指向原先的尾部节点
*/
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
2.3、acquireQueued
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
//返回node的prev
final Node p = node.predecessor();
//只有排在head节点之后的线程才能尝试去获取锁
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
/**
* shouldParkAfterFailedAcquire(p, node) 这个方法决定了当前线程是否要park
*/
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()){
interrupted = true;
}
}
} finally {
if (failed)
cancelAcquire(node);
}
}
2.3.1 shouldParkAfterFailedAcquire
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
//ws=-1
if (ws == Node.SIGNAL)
//当一个节点的上一个节点的waitStatus等于-1的时候,当前节点需要阻塞
return true;
if (ws > 0) {
do {
/**
* 把当前节点的上一个节点从链表中拿掉
* 说明当一个节点的waitStatus大于0的时候,说明这个节点不想再等待了,所以就应该把它从链表中拿掉
*/
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/**
* 更新上一个节点的waitStatus为-1
*
* 说明当上一个节点的waitStatus除了上面两种情况 都要更新waitStatus为-1
*
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}