快速一覽
- 基礎(chǔ)定義
- 前置知識:鎖實(shí)現(xiàn)的原理——LockSupport
- AQS隊(duì)列管理器
- 公平鎖和非公平鎖
- 共享鎖與排他鎖
- 參考文獻(xiàn)
- 未完待續(xù)
基礎(chǔ)定義
AQS:AbstractQueuedSynchronizer 抽象隊(duì)列同步器,是所有鎖的基礎(chǔ)。
前置知識:鎖實(shí)現(xiàn)的原理——LockSupport
Java 的線程阻塞和喚醒是通過 Unsafe 類的 park 和 unpark 方法做到的。
public class Unsafe {
...
public native void park(boolean isAbsolute, long time);
public native void unpark(Thread t);
...
}
鎖可以暫停線程的奧秘所在正是因?yàn)殒i在底層調(diào)用了 park 方法。
線程對象 Thread 里面有一個(gè)重要的屬性 parkBlocker(volatile修飾),它保存當(dāng)前線程因?yàn)槭裁炊?park。當(dāng)線程被 unpark 喚醒后,這個(gè)屬性會被置為 null。Unsafe.park 和 unpark 并不會幫我們設(shè)置 parkBlocker 屬性,負(fù)責(zé)管理這個(gè)屬性的工具類是 LockSupport,它對 Unsafe 這兩個(gè)方法進(jìn)行了簡單的包裝。
class LockSupport {
...
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
U.park(false, 0L);
setBlocker(t, null); // 醒來后置null
}
public static void unpark(Thread thread) {
if (thread != null)
U.unpark(thread);
}
}
...
}
AQS隊(duì)列管理器
內(nèi)部主要有兩個(gè)部分:持有當(dāng)前鎖的線程和統(tǒng)計(jì)的次數(shù)、維持競爭失敗的鎖的隊(duì)列。
基本原理:當(dāng)前資源state=0,線程會試圖獲取鎖,并通過CAS修改資源的state,若成功從0-1,那么當(dāng)前鎖的持有線程將改為當(dāng)前線程(exclusiveOwnerThread原本為null)。之后其他線程競爭鎖時(shí),先看state是不是0,不是的話再看持有者是不是自己,不是的話就被記錄到一個(gè)雙向隊(duì)列里面去(失敗者隊(duì)伍)。當(dāng)前鎖被釋放后,會喚醒隊(duì)首的線程,讓它去獲取。
公平鎖和非公平鎖
公平鎖會在隊(duì)伍有其他線程的時(shí)候進(jìn)入隊(duì)列等待;非公平鎖會先去競爭一次,失敗了才等待。(根據(jù)我看可重入鎖的代碼,他其實(shí)是競爭了兩次,但是道理是一樣的)
非公平鎖就是搶奪在隊(duì)首線程由park()方法返回到加鎖這中間的可能性。
==Q:如果被搶走了,這時(shí)候這個(gè)線程待在隊(duì)首還是重新排隊(duì)呀?==
A:在隊(duì)首,可以看到獲取鎖AcquireQueued()的方法是一個(gè)自旋的方法,如果沒有獲取鎖就會一直嘗試獲取。
共享鎖與排他鎖
ReentrantLock的鎖是排他鎖,一個(gè)線程持有,其它線程都必須等待。
而 ReadWriteLock里面的讀鎖不是排他鎖,它允許多線程同時(shí)持有讀鎖,這是共享鎖。
共享鎖和排他鎖是通過 Node 類里面的 nextWaiter 字段區(qū)分的(EXCLUSIVE和SHARED)。
class AQS {
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
boolean isShared() {
return this.nextWaiter == SHARED;
}
}
//nextWaiter還有其他功能。在等待隊(duì)列里面,它表示下一個(gè)node
參考文獻(xiàn)
鏈接:https://zhuanlan.zhihu.com/p/52280869
鏈接:https://zhuanlan.zhihu.com/p/43423666
未完待續(xù)
- AQS隊(duì)列維護(hù)源碼
- 條件變量地方不明白
- CAS