一、简介
AQS全称AbstractQueuedSynchronizer,在java中多线程工具包JUC是基于AQS实现的
技术核心:共享(volatile)state + 双向链表
实现方法:CAS操作
设计模式:模板模式(Template Pattern):父类画模,子类重写
二、源码分析
下面通过ReentrantLock源码进行分析:
- sync调用了lock方法,以下lock()方法具体实现:
final void lock() {
if (compareAndSetState(0, 1)) //第一个线程进来通过CAS操作更新为1
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1); //否则调用acquire()方法
}
- 跟进到acquire()方法中:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
可以看出又调用了自身的tryAcquire(arg)方法(拿到锁),跟进到里面发现又调用了nonfairTryAcquire(int acquires)
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); //AQS核心数值 state出场
//state为0无人上锁
if (c == 0) {
//CAS操作将0改为1,给线程上锁
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;
}
假如新进线程没有拿到锁调用acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法,先看addWaiter()方法:
private Node addWaiter(Node mode) {
//获取当前线程的node节点
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
if (pred != null) { //队列末尾不为空
node.prev = pred; //将新节点的前置节点设置在等待队列的末端
if (compareAndSetTail(pred, node)) {//CAS操作设置新节点为tail末端
pred.next = node;
return node;
}
}
enq(node);
return node;
}
acquireQueued()方法:
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);
}
}
- 配一张图 配合理解
三、总结
AQS(AbstractQueuedSynchronizer)的核心就是CAS操作双向链表(head and tail)