Java併發編程原理 - Unsafe && LockSupport類及AQS同步器的設計

[相關源碼]

(https://github.com/Wasabi1234/Java-Concurrency-Progamming-Tutorial)java

1 Unsafe類的park和unpark

public native void park(boolean var1, long var2);
public native void unpark(Object var1);
  • park方法用來阻塞一個線程,第一個參數用來指示後面的參數是絕對時間仍是相對時間,true表示絕對時間,false表示今後刻開始後的相對時間.調用park的線程就阻塞在此處.
  • unpark用來釋放某個線程的阻塞,線程用參數var1表示

舉個例子:
git

2 LockSupport

直接使用Unsafe仍是有諸多不便之處,所以lock包提供了一個輔助類LockSupport封裝了park和unpark程序員

舉個例子:
github

能夠看出,使用LockSupport要比直接只用Unsafe更加便捷。多線程

此外,LockSupport還能夠用來給線程設置一個Blocker對象,便於調試和檢測線程,其原理是使用Unsafe的putObject方法直接設置Thread對象的parkBlocker屬性,並在合適的時候讀取這個Blocker對象,例子以下:ui

3 AQS同步器

各類鎖ReentrantLock、ReentrantReadWriteLock以及各類同步器諸Semaphore、CountDownLatch等,核心都是AbstractQueuedSynchronizerthis

  • 要真正從源頭理解AQS,建議仔細閱讀該類的設計者的論文
    http://gee.cs.oswego.edu/dl/papers/aqs.pdf線程

    3.1 使用 AQS 手寫排它鎖

    讓咱們先具體感知它是如何使用的。設計

這裏有一個很是簡單的例子SimpleLock,實現了一個最簡單的排它鎖。3d

  • 當有線程得到鎖時,其餘線程只能等待
  • 當這個線程釋放鎖時,其餘線程能夠競爭獲取鎖


運行結果代表,經過簡單的幾行代碼,就實行了一個鎖的全部功能。

根據JUC做者的建議,AQS的使用方法要遵循上面這個模式。

使用一個內部類Sync來繼承AQS,並實現AQS的相關方法

通常是

  • tryAcquire
  • tryRelease(排它鎖)

或者

  • tryAcquireShared
  • tryReleaseShared(共享鎖)

在內部使用代理模式實現鎖的功能

這樣可讓暴露出的同步、互斥方法名由程序員自行決定。
例如各類鎖可使用

  • lock
  • unlock

Semaphore可使用

  • acquire
  • release

CountDownLatch可使用

  • await
  • countDown

2 AQS基本原理

要實現一個同步器,須要三個條件:

  1. 一個同步狀態值,且可原子操做該狀態值.顯然CAS勝任
  2. 阻塞線程和解除阻塞線程的機制,能夠用LockSupport來實現
  3. 維護一個阻塞線程的隊列,並在隊列的每一個節點中存儲線程的狀態等信息

讓咱們看看AQS又是如何設計知足的這三個條件。

2.1 狀態值及相應的操做方法

private volatile int state;

protected final int getState() {
    return state;
}

protected final void setState(int newState) {
    state = newState;
}

protected final boolean compareAndSetState(int expect, int update) {
    // See below for intrinsics setup to support this
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

state 爲 volatile int型,它的CAS方法,提供原子的比較更新操做。

通常,AQS認爲

  • state == 0 時,同步器處於釋放狀態,多線程此時可競爭獲取同步器
  • state ≠ 0 時,同步器處於已獲取狀態,後續線程需進入隊列,等待同步器(可重入同步器容許獲取同步器的線程再次進入該同步器,此時使用state計數)
  • 固然,不少狀況下,程序員也可本身定義state的值的含義,特別是在實現讀寫鎖時,須要將state一分爲二的用。

2.2 阻塞和解除阻塞

LockSupport 提供了阻塞和解除阻塞的功能。所以,全部同步器的阻塞操做其實都是基於LockSupport的,也就是基於Unsafe的park和unpark方法的。

2.3 線程等待隊列

AQS內部提供了一個Node類型,它是用來造成「線程等待隊列」的節點類型,以及一個由Node類型組成的隊列。

相關文章
相關標籤/搜索