1.AQS是什么?
AQS是AbstractQueuedSynchronizer的简称,它是一个java的底层同步工具类,用一个int类型的变量表示同步状态,并且提供了一系列的CAS操作来管理这个同步状态
2.同步队列
同步队列是AQS中 很重要的一部分,它是一个双端队列,遵循FIFO原则,主要的作用是用来存放在锁上阻塞的线程,当一个线程尝试获取锁的时候,如果已经被占用的话,那么当前线程会构造出一个Node节点,放到同步等待队列的尾部,队列的头结点是成功获取锁的节点,当头结点释放锁的时候会唤醒下一个节点去获取锁
AbstractQueuedSynchronizer中Node内部类分析
static final class Node {
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
/**
* 等待的状态
*/
volatile int waitStatus;
/**
* 当前节点的前驱节点
*/
volatile Node prev;
/**
* 当前节点的下一个节点
*/
volatile Node next;
/**
* 当前节点的线程
*/
volatile Thread thread;
/**
* 等待队列中的下一个节点
*/
Node nextWaiter;
/**
* 返回这个节点的等地状态是否是共享状态
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* 节点判空
*
* @return the predecessor of this node
*/
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // Used to establish initial head or SHARED marker
}
Node(Thread thread, Node mode) { // Used by addWaiter
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}
AbstractQueuedSynchronizer中 addWaiter方法详解
/**
* 创建一个等待队列
*/
private Node addWaiter(Node mode) {
// 以给定的模式为当前线程创建一个Node节点信息
Node node = new Node(Thread.currentThread(), mode);
// 尾节点
Node pred = tail;
// 如果尾节点不为null,则设置当前节点的前驱节点为尾节点,在利用cas操作设置尾节点
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
// 如果尾节点为null的话则将当前node节点设置为尾节点
enq(node);
return node;
}
/**
* 将节点安全的插入队列,必要时初始化队列
*/
private Node enq(final Node node) {
for (;;) {
Node t = tail;
// 如果尾节点是null的话必须初始化等待队列
if (t == null) { // Must initialize
// 创建一个等待队列出来,利用CAS操作设置头结点,头尾相连
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
3.独占式获取锁
/**
* 独占式获取锁的方法
*/
public final void acquire(int arg) {
// 尝试获取锁,如果没获取到,就加入到等待同步队列中
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
/**
* 首先判断其前驱节点释放为头节点&是否成功获取同步状态,两个条件都成立,则将当前线程的节点设
置为头节点,如果不是则利用LockSuport.park()方法将当前线程挂起,等待前驱节点的呼唤
*/
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);
}
}
4.独占式释放锁分析
/**
* 释放锁
*/
public final boolean release(int arg) {
// 尝试释放锁
if (tryRelease(arg)) {
Node h = head;
// 释放成功的话则判断头结点是否不等于null,等待状态是否不等于0
if (h != null && h.waitStatus != 0)
// 调用本地方法唤醒下一个节点
unparkSuccessor(h);
return true;
}
return false;
}
5.共享式获取锁 释放锁和独占式雷同,不一样的地方是头结点释放锁的话是唤醒后面所有的等待节点