一、AQS
AbstractQueuedSynchronizer是一个抽象同步框架,主体由等待队列和共享变量state构成。AQS包括两种队列:
等待队列和条件队列。
支持特性包括:
- 1.阻塞等待队列
- 2.共享/独占
- 3.公平/非公平
- 4.可重入
- 5.允许中断
1.1 等待队列和条件队列
1.1.1 等待队列
主要用于维护获取锁失败的线程。
等待队列有prev和next两个属性,是一个基于双向链表的队列。
1.1.2 条件队列
调用await()方法时会释放锁,然后线程会加入条件队列,调用signal唤醒时,会把条件队列中的节点移动到等待队列中。
条件队列通过nextWaiter连接,是一个单向链表。
1.2 源码分析
1.2.1 基本属性
// 头结点
private transient volatile Node head;
// 尾节点
private transient volatile Node tail;
// 共享变量
private volatile int state;
通过state判断锁状态以及实现可重入锁。
1.2.2 内部类节点
static final class Node {
// 共享和独占标识
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
// 节点状态
volatile int waitStatus;
// 前置和后置节点
volatile Node prev;
volatile Node next;
Node nextWaiter;
}
根据头尾节点可以看出,等待队列是一个基于双向链表的队列。节点存在共享和独占两种状态。
1.2.3 waitStatus状态
// 表示线程获取锁的请求已取消
static final int CANCELLED = 1;
// 表示线程已准备好等待资源释放
static final int SIGNAL = -1;
// 表示节点在等待队列中,等待唤醒
static final int CONDITION = -2;
// 在共享情况下才会使用
static final int PROPAGATE = -3;
二、ReentrantLock
ReentrantLock是基于AQS的一种应用实现。它是可重入的互斥锁,类似Synchronized,但比Synchronized更加灵活。
2.1 源码分析
2.1.1 非公平锁加锁过程
// 加锁方法
public void lock() {
sync.acquire(1);
}
// 获取锁及入队
public final void acquire(int arg) {
// 先尝试获取锁,再进行入队操作
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// 获取非公平锁
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 判断state状态
if (c == 0) {
// 尝试设置state
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;
}
// 设置尾节点
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)) {
pred.next = node;
return node;
}
}
// 尾结点为空将节点插入队列
enq(node);
return node;
}
// 节点加入队列,必要时初始化队列
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
// 入队
final boolean acquireQueued(final Node node, int arg) {
boolean interrupted = false;
try {
for (;;) {
// 获取上一节点
final Node p = node.predecessor();
// 判断上一节点是否是头节点,并尝试获取一次锁
if (p == head && tryAcquire(arg)) {
// 设置为头节点
setHead(node);
p.next = null; // help GC
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node))
// 判断并为线程设置中断状态
interrupted |= parkAndCheckInterrupt();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
// 设置waitStatus,保持SIGNAL状态
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
// 获取前一节点的状态
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
// 前一节点为SIGNAL状态,可以安全调用park()方法
return true;
if (ws > 0) {
// 如果前一节点为CANCELLED状态,则说明前一节点由于某些情况中断而取消,需要跳过这些节点
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 通过CAS设置状态为SIGNAL
pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
}
return false;
}
2.1.2 非公平锁解锁过程
public final boolean release(int arg) {
if (tryRelease(arg)) {
// 解锁后获取头结点
Node h = head;
// 头节点不为空且节点不在等待状态时,使用unpark唤醒线程
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
// state-1
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 若state为0,则锁已释放
if (c == 0) {
free = true;
// 取消独占锁的线程
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}