天天看點

ReentrantLock 源碼分析 - 并發基礎類

前言

接下來會用 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

裡面存放有具體的線程,簡易圖如下:

ReentrantLock 源碼分析 - 并發基礎類

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 過程中的作用:

ReentrantLock 源碼分析 - 并發基礎類

假設有三個線程同時去調用

dealShareResource

方法,會去擷取鎖, 如果

thread1

先搶到鎖,那麼其餘的線程(

thread2,thread3

)就會放到 AQS 隊列當中,其他細節這裡先不提。

3.4 AbstractQueuedSynchronizer 的屬性

我們知道

ReentrantLock

是一個可重入鎖,而它的這個特性就是基于

AbstractQueuedSynchronizer

state

屬性

屬性定義

private volatile int state;
           
  • 作用一
    • 一個線程過來,如果

      state

      為 0 表示鎖沒有被占用
    • 調用

      compareAndSetState(0, 1)

      方法
    • 期望獲得的是 0,如果是 0,就把

      state

      更新為 1
  • 作用二
    • 一個線程 A 過來, 如果

      state > 0

      ,表示鎖被線程 B 占用了,
    • 然後判斷 線程A 是否就是 線程 B
    • 如果是

      state++

      , 否則放入 AQS 隊列

總結

本文是對閱讀

ReentrantLock

源碼之前做的準備工作, 簡單了解了三個類的基本作用:

  • sun.misc.Unsafe
  • java.util.concurrent.locks.LockSupport
  • java.util.concurrent.locks.AbstractQueuedSynchronizer

他們的調用關系是由下而上。

ReentrantLock

持有

AbstractQueuedSynchronizer

具體實作,通過調用

ReentrantLock

lock

unlock

方法,最終會去調用

AbstractQueuedSynchronizer

相應的方法,最後實作同步功能。