java AQS源码解析
大部分的锁,像可重入锁,读写锁,countdownLatch等都是基于AQS实现。
1:AbstractQueuedSynchronizer是一个抽象方法,有一些方法是需要子类进行实现的,这里面就用到了模板的设计模式(不会请自行百度)
2:内部类Node节点,存储当线程获取不到锁的时候,进行锁的保存形成一个队列(FIFO),当释放锁的时候,就会在Node节点开始获取线程,拿到锁。
首先介绍node节点

构造函数,三个方法。第一个是空的,什么也没有操作。
第二个 thread赋值给Thread,int 赋值到waitStatus。
第二个 thread赋值给Thread,mode赋值到nextWaiter。
线程等待模式
SHARED:以共享的方法等待锁,一把锁可以锁多个线程
EXCLUSIVE:以互斥的方式等待锁,一把锁只能锁一个线程。
线程的状态
CANCELLED:等于1,表示线程获取锁已经取消了。
SIGNAL:等于-1,表示线程在等待,等待获取锁。。
CONDITION:等于-2,表示线程等待某一条件被满足(condition)。
PROPAGATE:等于-3,线程处于共享模式的时候,才会被用到。
waitStatus:该字段表示线程的状态,被volatile修饰。因为是int,所以默认值是0。
其他成员变量
prev:该节点的上一个节点,类型是Node。
next:该节点的下一个节点,类型是Node。
thread:代表该节点的线程,类型是Thread。
nextWaiter:等待condition条件的node节点。类型是node。
介绍AQS类中的重要方法
private transient volatile Node head; //表示当前的首节点。
private transient volatile Node tail; //表示当前的尾节点。
private volatile int state; //这个是是重点的属性,标识状态。
acquire方法是一个重点方法
//调用tryAcquire方法,其次会调用addWaiter方法,在调用acquireQueued方法,将节点添加到队列中。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//protected修饰的,都是需要子类去实现的,这个就是使用了模板方法
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode); //创建处一个节点
Node pred = tail; //获取尾节点 if (pred != null) { node.prev = pred; //将尾节点设置成为当前节点的上一节点 if (compareAndSetTail(pred, node)) { //通过CAS获取到是否修改成功,这里面主要是多个线程在获取锁 pred.next = node; return node; } } enq(node); //当没有获取到锁的时候,执行enq方法 return node; }
private Node enq(final Node node) {
for (;;) { //设置一个死循环
Node t = tail; //获取尾节点
if (t == null) { //如果为空则将首节点设置为尾节点
if (compareAndSetHead(new Node()))
tail = head;
} else { //否则就重复上面的操作,一直不成功就一直在操作,直到成功为止
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
//上面的操作只是封装Node节点,下面是将节点存放到队列当中
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) { //定义一个死循环
final Node p = node.predecessor(); //代码在Node类中,获取当前节点的上一节点,如果存在就返回,不存在就报错。
if (p == head && tryAcquire(arg)) { //如果上一节点是首节点,并且获取到了锁。
setHead(node); //首节点是当前节点
p.next = null; // help GC //将上一节点的下一节点设置为null
failed = false; //设置为false,并且返回false对象
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) && //说明上一节点不是首节点,
parkAndCheckInterrupt()) //阻塞当前的线程,调用了LuckSupport.park方法
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {//pred是上一节点,node是当前节点
int ws = pred.waitStatus; //获取上一节点的状态
if (ws == Node.SIGNAL) //如果是-1,则返回true
return true;
if (ws > 0) { //如果是大于0,说明上一节点已经放弃获取锁了
do {
node.prev = pred = pred.prev; //然后就去找上一节点的上一节点,直到找到状态小于0的
} while (pred.waitStatus > 0);
pred.next = node; //将符合条件的节点,下一节点设置成当前节点。
} else {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL); //如果ws小于0,则将上一节点通过CAS设置成-1
}
return false;
}
以上就是将Node节点添加队列的尾节点。
以下就是释放独占式的锁
public final boolean release(int arg) { if (tryRelease(arg)) { //该方法是protected修饰的,需要子类实现 Node h = head; //获取首节点 if (h != null && h.waitStatus != 0) //判断是否等于null,状态不等于0 unparkSuccessor(h); return true; } return false; }
private void unparkSuccessor(Node node) {
int ws = node.waitStatus; //获取当前的状态
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0); //如果小于0,设置为0
Node s = node.next; //获取该节点的下一个节点
if (s == null || s.waitStatus > 0) { //当下一个节点为空,或者是大于0的时候,说明该节点不符合规则,就找符合节点的节点
s = null;
for (Node t = tail; t != null && t != node; t = t.prev) //现在是从后面往前面找,找到小于0的节点
if (t.waitStatus <= 0)
s = t; //将该节点的下一个节点设置成为找的小于0的节点
}
if (s != null)
LockSupport.unpark(s.thread); //调用LockSupport.unpark方法
}
共享式的获取锁,可以多个线程获取锁
public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) //tryAcquiredShard方法是protected修饰的,子类具体方法。 doAcquireShared(arg); //当小于0的时候,会调用该方法 }
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED); //node.Shared是一个new node。和独占式的以为区别是Node.EXCLUSIVE
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor(); //获取当前节点的上一个节点
if (p == head) { //上一节点是首节点
int r = tryAcquireShared(arg); //去执行子类的该方法,尝试是否获取到了锁,
if (r >= 0) { //如果返回值大于0,说明获取到了锁
setHeadAndPropagate(node, r);
p.next = null; //将上一节点的下一节点设置为null
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
//该代码和独占式的代码一样
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; //获取首节点
setHead(node); //将当前节点设置为首节点
//首节点还不是当前的节点,判断之前的首节点和现在的首节点的状态是否小于0
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next; //获取当前状态的下一个节点
if (s == null || s.isShared()) //如果当前节点的下一个节点是null,获取是判断是否是共享式的,则调用doRealseaShard方法
doReleaseShared();
}
}
共享式的释放锁
public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) { //该方法是protected修饰的,具体实现是父类进行的 doReleaseShared(); //当释放成功时,调用该方法 return true; } return false; }
private void doReleaseShared() {
for (;;) { //定义死循环
Node h = head; //获取首节点
if (h != null && h != tail) {
int ws = h.waitStatus; //获取当前锁的状态
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) //将-1变成0
continue;
unparkSuccessor(h); //执行的方法和独占式的一样
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) //将0变成-3
continue;
}
if (h == head) //如果是首节点没有变则返回
break;
}
}
以上就是个人对AQS的理解。

浙公网安备 33010602011771号