AQS(AbstractQueuedSynchronizer)即队列同步器,它是J.U.C包下构建同步(锁)操作基础组件。其大体组成如下(以下描述基于JDK 1.8):
public abstract class AbstractQueuedSynchronizer {
private transient volatile Node head; // 头节点,队列为null时有元素入队,head指向一个空node对象
private transient volatile Node tail; //记录最后一个节点
private volatile int state;
public class ConditionObject implements Condition, java.io.Serializable {
// 这里暂不做分析
}
// 线程队列的节点, 队列的入队、出队逻辑在AQS类中实现
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;
// 表示线程因为等待某个条件而被阻塞.(用于Condition的await等待)
static final int CONDITION = -2; //
// 表示锁的下一次获取可以无条件传播(共享锁中用到)
static final int PROPAGATE = -3;
volatile int waitStatus; // 等待状态
volatile Node prev; // 前驱结点
volatile Node next; // 后继结点
volatile Thread thread;
Node nextWaiter; // 等待状态的下一个节点
Node() { // Used to establish initial head or SHARED marker
}
// 入队时使用,mode匹配SHARED/EXCLUSIVE (共享/排他锁)
Node(Thread thread, Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}
}
1、acquire(int arg)方法获取锁
public final void acquire(int arg) {
if (!tryAcquire(arg) && // 由子类实现,获取到同步则返回true
// 未获取到同步状态,先将当前节点加入阻塞队列
// 再一次尝试获取同步,若失败返回true, 阻塞当前线程
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
2、该如何获取锁由子类实现,如果获取到了锁则返回true
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
3、如果没有获取到锁,则会将当前节点加入到等待队列中
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// 尝试一次入队,若失败,则转到enq方法多次尝试
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
// 循环尝试入队,直至入队成功
private Node enq(final Node node) {
for (;;) {
Node t = tail;
// 当头(尾)节点为null时,先使头尾节点指向一个空node对象
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
4、入队成功后,可能之前持有锁的线程可能已经释放锁了,所以需要 acquireQueued(addWaiter(Node.EXCLUSIVE), arg))判断当前线程是否可以拿到锁了,不能则返回true,acquire方法中调用selfInterrupt()阻塞线程
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 获取节点的前驱结点,判断是否头节点
final Node p = node.predecessor();
// 如果获取锁成功,则返回false,线程执行,不阻塞
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);
}
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
if (ws > 0) {
// 移除前驱结点中已取消的节点
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
1、释放锁与获取锁的具体实现一样,都是转交由子类实现
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
2、如果锁可以释放,则需要唤醒队列中下一个线程
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
// 如果队列中后继结点已取消,则需要重新找到队列中最靠近当前节点的未取消的节点(waitStatus <= 0)
// 如果后继结点为null,则下面这个if块什么都不做
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
// 队列中排有其他未取消的线程时才会唤醒最靠近的节点
if (s != null)
LockSupport.unpark(s.thread);
}
public class SynBuilder {
public static void main(String[] args) {
SynBuilder builder = new SynBuilder();
Thread t1 = builder.newThread("线程1");
Thread t2 = builder.newThread("线程2");
t1.start();
t2.start();
}
private final Syn syn = new NoFairSyn();
public void lock() {
syn.acquire(1);
System.out.println(Thread.currentThread().getName() + " : 获得了锁");
}
public void unlock() {
syn.release(1);
System.out.println(Thread.currentThread().getName() + " : 获得了释放了锁");
}
private static class Syn extends AbstractQueuedSynchronizer {
}
private static class NoFairSyn extends Syn {
@Override
protected boolean tryAcquire(int acquires) {
Thread ct = Thread.currentThread();
int state = getState();
if(state == 0) { // 未加锁
if(compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(ct);
return true;
}
// 判断锁是否当前线程持有
} else if(getExclusiveOwnerThread() == ct) {
int acquiresNum = acquires + getState();
if(acquiresNum < 0) {
throw new IllegalArgumentException();
}
// 锁为当前线程持有,所以不用CAS
setState(acquiresNum);
return true;
}
return false;
}
@Override
protected boolean tryRelease(int acquires) {
if(getExclusiveOwnerThread() != Thread.currentThread()) {
throw new IllegalMonitorStateException();
}
int state = getState() - acquires;
boolean free = false;
if(state == 0) {
setExclusiveOwnerThread(null);
free = true;
}
setState(state);
return free;
}
}
public Thread newThread(String name) {
return new Thread(() -> {
System.out.println(name + " 正在尝试获取锁");
lock();
lock();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
unlock();
unlock();
}
}, name);
}
}
输出为
线程1 正在尝试获取锁
线程2 正在尝试获取锁
线程1 : 获得了锁
线程1 : 获得了锁
线程1 : 获得了释放了锁
线程1 : 获得了释放了锁
线程2 : 获得了锁
线程2 : 获得了锁
线程2 : 获得了释放了锁
线程2 : 获得了释放了锁
死磕Java并发