前言
接下來會用 3-4 篇文章來分析
ReentrantLock
的源碼,本文先來打點基礎。
閱讀本文之前需了解以下内容:
- 原子性的概念
- CAS 的概念
-
是獨占鎖且可重入ReentrantLock
-
既可以是非公平鎖,也可以是公平鎖ReentrantLock
以上小知識也可以參考上一篇文章ReentrantLock 源碼分析 - 并發小知識
正文
分析
ReentrantLock
之前,需要簡單了解以下三個基礎類:
- sun.misc.Unsafe
- java.util.concurrent.locks.LockSupport
- java.util.concurrent.locks.AbstractQueuedSynchronizer
這三個類,本文會粗略提一下他們的功能,有個大概印象即可, 第三個類是重點, 後面的文章還會詳細講到。
1. Unsafe 類
Unsafe
類位于 JDK 的 rt.jar 包中, 它提供了硬體級别的 原子性 操作,
Unsafe
類中的方法都是 native 方法。
我們主要看下面三個方法:
// 比較 Object 中偏移量為 offset 的變量的值是否與 expect 相等,
// 如果相等則使用 update 更新并傳回 true
// 如果不相當,傳回 false
public final native boolean compareAndSwapInt(Object o, long offset, int expect, int update);
// 阻塞目前線程
public native void park(boolean var1, long var2);
// 喚醒調用 park 方法而阻塞的線程
public native void unpark(Object var1);
2. LockSupport 類
LockSupport
類中也有相應的
park
和
unpark
方法,内部實作也是基于
Unsafe
類對應的方法, 當然作用也是一樣的。
public static void park(Object blocker) {
// 省略部分代碼
unsafe.park()
}
public static void unpark(Thread thread) {
// 省略部分邏輯
unsafe.unpark()
}
3. AbstractQueuedSynchronizer 類
AbstractQueuedSynchronizer
是分析的重點, 來詳細看下。
3.1 AbstractQueuedSynchronizer 的方法
AbstractQueuedSynchronizer
類通過調用
LockSupport
和
Unsafe
對應的方法去實作以下三個功能。
// 擷取獨占資源
public final void acquire(int arg) {
// 最終會調用
LockSupport.park();
}
// 釋放獨占資源
public final boolean release(int arg) {
// 最終會調用
LockSupport.unpark();
}
// CAS 操作
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
3.2 AbstractQueuedSynchronizer 簡單介紹
AbstractQueuedSynchronizer
是一個抽象類,中文可以翻譯為 抽象同步隊列, 簡稱 AQS,是一個雙向隊列,隊列中的節點定義為
Node
,
Node
裡面存放有具體的線程,簡易圖如下:
AbstractQueuedSynchronizer
是實作
ReentrantLock
,
ReentrantReadWriteLock
,
CountDownlatch
等同步器的基礎。
3.3 AbstractQueuedSynchronizer 的作用
我們就拿
ReentrantLock
來說明
AbstractQueuedSynchronizer
的作用。
ReentrantLock
内部持有
AbstractQueuedSynchronizer
相應實作的引用。
// ReentrantLock 源碼
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
// 省略部分内容
}
}
來看一個
ReentrantLock
的具體使用
ReentrantLock lock = new ReentrantLock();
// 對共享資源進行操作
public void dealShareResource() throws InterruptedException {
try {
lock.lock();
// doSomething
} finally {
lock.unlock();
}
}
從代碼使用上看,并不能看出 AQS 到底起到了什麼作用,下面用一張圖來描述 AQS 在 lock 過程中的作用:
假設有三個線程同時去調用
dealShareResource
方法,會去擷取鎖, 如果
thread1
先搶到鎖,那麼其餘的線程(
thread2,thread3
)就會放到 AQS 隊列當中,其他細節這裡先不提。
3.4 AbstractQueuedSynchronizer 的屬性
我們知道
ReentrantLock
是一個可重入鎖,而它的這個特性就是基于
AbstractQueuedSynchronizer
的
state
屬性
屬性定義
private volatile int state;
- 作用一
- 一個線程過來,如果
為 0 表示鎖沒有被占用state
- 調用
方法compareAndSetState(0, 1)
- 期望獲得的是 0,如果是 0,就把
更新為 1state
- 一個線程過來,如果
- 作用二
- 一個線程 A 過來, 如果
,表示鎖被線程 B 占用了,state > 0
- 然後判斷 線程A 是否就是 線程 B
- 如果是
, 否則放入 AQS 隊列state++
- 一個線程 A 過來, 如果
總結
本文是對閱讀
ReentrantLock
源碼之前做的準備工作, 簡單了解了三個類的基本作用:
- sun.misc.Unsafe
- java.util.concurrent.locks.LockSupport
- java.util.concurrent.locks.AbstractQueuedSynchronizer
他們的調用關系是由下而上。
ReentrantLock
持有
AbstractQueuedSynchronizer
具體實作,通過調用
ReentrantLock
的
lock
和
unlock
方法,最終會去調用
AbstractQueuedSynchronizer
相應的方法,最後實作同步功能。