类结构
static final class NonfairSync extends Sync {
}
一、加锁
1、lock()
final void lock() {
//先尝试直接加锁
if (compareAndSetState(0, 1))
//成功了就结束方法
setExclusiveOwnerThread(Thread.currentThread());
else
//失败了调用acquire(1)
acquire(1);
}
2、acquire(int arg)
public final void acquire(int arg) {
//再次尝试加锁,加锁失败将该线程加入AQS队列。
//这两个操作进行完之后,将该线程打断,让出时间片
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
3、tryAcquire(int acquires)
protected final boolean tryAcquire(int acquires) {
//调用不公平的acquire
return nonfairTryAcquire(acquires);
}
4、nonfairTryAcquire(int acquires)
final boolean nonfairTryAcquire(int acquires) {
//获取当前线程和当前锁的owner的状态
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//如果没有加锁,就加锁
//这里体现了不公平性:外来线程可以直接加锁,不用先去检查AQS队列
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//如果加了锁并且锁的owner就为当前线程时,状态值+1(表示锁重入)
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//否则返回false。表示线程竞争锁失败。接着调用acquireQueued、addWaiter将其加入AQS队列
return false;
}
5、addWaiter(Node mode)
其中,head
和tail
都可以看作指向Dummy的指针。
private Node addWaiter(Node mode) {
//将当前线程关联到一个模式为独占模式的Node对象上
Node node = new Node(Thread.currentThread(), mode);
//如果 tail 不为 null, cas 尝试将 Node 对象加入 AQS 队列尾部
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
6、enq(final Node node)
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) {
//此时head = tail = null,说明队列中还没有元素
//将tail和head都从null->dummy
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
//将node对象加入AQS队列尾部,将tail从t设置成node
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
7、acquireQueued(final Node node, int arg)
node结点上关联的是当前线程(和锁的owner不同),arg一般是1,表示加锁的值。
线程在这个方法里,会死循环不断尝试获得锁,失败两次后进入park阻塞。
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
//在这个死循环中,
final Node p = node.predecessor();
/*
获取当前线程的前驱线程
若前驱==head,说明当前线程就为AQS队列中的第一个线程ÿ