目錄
1. AbstractQueuedSynchronizer 介紹
1. AbstractQueuedSynchronizer 介紹
抽象同步隊列 AbstractQueuedSynchronizer ,簡稱 AQS,它是實現阻塞鎖和其他基於先入先出(FIFO)等待隊列的同步組件。
併發包中鎖的底層實現(如 ReentrantLock )的底層實現就是使用 AQS 實現的。
2. AQS 內部結構
i. AQS 繼承自 AbstractOwnableSynchronizer
ii. 類 ConditionObject 主要提供一種條件,由子類決定是否支持獨佔模式
iii. 類 Node,作爲先入先出(FIFO)阻塞隊列裏面的每個節點
3. 狀態信息 state
AQS 維持了一個單一的狀態信息 state,可通過 getState()、setState(int newState)、compareAndSetState(int expect, int update) 方法來修改 state 的值。
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 狀態信息
private volatile int state;
// 返回當前的狀態值。該操作擁有 volatile 讀的內存語義
protected final int getState() {
return state;
}
//設置狀態值
protected final void setState(int newState) {
state = newState;
}
// 通過 unsafe 類原子的設置同步狀態值爲給定的 update 值,設置成功後返回true,否則返回false
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
state 作用舉例:
ReentrantLock 中,state 表示當前線程獲取鎖的可重入次數。
ReentrantReadWriteLock 中,state 高 16 位表示獲取讀鎖的次數,低 16 爲表示獲取寫鎖的線程的可重入次數。
4. 內部類 Node
4.1 Node 類源碼
static final class Node {
// 標記符,共享模式下的等待節點
static final Node SHARED = new Node();
// 標記符,獨佔模式下等待節點
static final Node EXCLUSIVE = null;
/**
* 等待狀態值
* 1 表示線程已經被取消
* -1 表示一個後繼節點的線程需要喚醒
* -2 表示線程等待在某種條件下
* -3 表示下一次共享式獲取狀態的操作應該無條件的傳播
*/
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
// 狀態字段,取上述 4 個狀態值。值爲 0,表示非以上狀態
volatile int waitStatus;
// 當前節點的前驅節點
volatile Node prev;
// 當前節點的後繼節點
volatile Node next;
// 節點關聯的線程
volatile Thread thread;
// 下一個處於等待條件的節點
Node nextWaiter;
// 判斷節點是否以共享模式等待
final boolean isShared(){
return nextWaiter == SHARED;
}
// 如果有前驅節點,則返回該節點
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() {
}
// addWaiter 使用。給線程添加等待模型
Node(Thread thread, Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
// Condition 使用,給線程添加等待條件
Node(Thread thread, int waitStatus) {
this.waitStatus = waitStatus;
this.thread = thread;
}
}
4.2 對 Node 的 CAS 操作
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long stateOffset;
private static final long headOffset;
private static final long tailOffset;
private static final long waitStatusOffset;
private static final long nextOffset;
static {
try {
stateOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
headOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("head"));
tailOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
waitStatusOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("waitStatus"));
nextOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("next"));
} catch (Exception ex) { throw new Error(ex); }
}
/**
* 使用 unsafe 類對 Node 進行原子更新。如果當前狀態值等於預期值,則以原子方式將同步狀態設置爲給定的更新值。
*/
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
private static final boolean compareAndSetWaitStatus(Node node,
int expect,
int update) {
return unsafe.compareAndSwapInt(node, waitStatusOffset,
expect, update);
}
private static final boolean compareAndSetNext(Node node,
Node expect,
Node update) {
return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
}
4.3 隊列中的 Node 操作
/**
* 將節點加入隊列,必要時進行初始化
*/
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) {
// 尾結點爲空,需要初始化
if (compareAndSetHead(new Node()))
tail = head;
} else {
// 尾結點不爲空,unsafe進行插入節點
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
/**
* 爲當前線程設置指定模式。並加入隊列
*/
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 void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}
/**
* 如果存在後繼節點則進行喚醒操作
*/
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
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);
}
5. 內部類 ConditionObject
ConditionObject 實現了 Condition 接口。Condition 對象是由 Lock 對象創建的。
/**
* 等待隊列中的頭結點
*/
private transient Node firstWaiter;
/**
* 等待隊列中的尾結點
*/
private transient Node lastWaiter;
ConditionObject 核心的兩個方法:await() 、signal()
5.1 await() 方法
- 當前線程進入等待狀態,直到被通知(signal)或中斷
- 當前線程將進入運行狀態且從 await() 方法返回的情況:
- 其他線程調用該 Condition 的 signal() 或 signalAll() 方法
- 其他線程調用 interrupt() 方法中斷當前線程
- 如果等待線程從 await() 方法返回,則該線程已經獲取了 Condition 對象所對應的鎖
5.2 signal() 方法
喚醒一個等待在 Condition 上的線程,該線程從等待方法返回前必須獲得與 Condition 相關聯的鎖
signal() 爲喚醒一個線程,signalAll() 爲喚醒所有等待的線程
6. 獲取和釋放資源的方法
獨享方式:acquire(int arg)、acquireInterruptibly(int arg)、release(int arg)
共享方式:acquireShared(int arg) 、acquireSharedInterruptibly(int arg)、releaseShared(int arg)
6.1 獨享方式
/**
* 獲取獨享鎖
* tryAcquire 需要子類重寫方法
*/
public final void acquire(int arg) {
// 嘗試獲取鎖,獲取成功返回 true,否則返回 false
if (!tryAcquire(arg) &&
// 沒有獲取則加入隊列尾部,並通過 LockSupport.park(this)掛起自己
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 進行自我中斷
selfInterrupt();
}
// 線程自我中斷
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
/**
* 試着釋放當前線程持有的獨佔鎖並喚醒後繼節點
*/
public final boolean release(int arg) {
// tryRelease 獨享式釋放同步狀態,需要子類重寫
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
/**
* 獲取獨佔鎖的可中斷模式
*/
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
// 當前線程如果中斷,則拋出中斷異常
throw new InterruptedException();
if (!tryAcquire(arg)) // 嘗試獲取鎖
// 獲取鎖失敗,則調用 doAcquireInterruptibly 獲取獨享鎖的可中斷模式
doAcquireInterruptibly(arg);
}
6.2 共享方式
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
// 獲取共享鎖的不中斷模式
doAcquireShared(arg);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}