AQS其實就是java.util.concurrent.locks.AbstractQueuedSynchronizer這個類。 閱讀Java的併發包原始碼你會發現這個類是整個java.util.concurrent的核心之一,也可以說是閱讀整個併發包原始碼的一個突破口。

比如讀ReentrantLock的原始碼你會發現其核心是它的一個內部類Sync:

整個包中很多類的結構都是如此,比如Semaphore,CountDownLatch都有一個內部類Sync,而所有的Sync都是繼承自AbstractQueuedSynchronizer。 所以說想要讀懂Java併發包的程式碼,首先得讀懂這個類。

AQS簡核心是通過一個共享變數來同步狀態,變數的狀態由子類去維護,而AQS框架做的是:

  • 執行緒阻塞佇列的維護
  • 執行緒阻塞和喚醒

共享變數的修改都是通過Unsafe類提供的CAS操作完成的。AbstractQueuedSynchronizer類的主要方法是acquirerelease,典型的模板方法, 下面這4個方法由子類去實現:

protected boolean tryAcquire(int arg)
protected boolean tryRelease(int arg)
protected int tryAcquireShared(int arg)
protected boolean tryReleaseShared(int arg)

acquire方法用來獲取鎖,返回true說明執行緒獲取成功繼續執行,一旦返回false則執行緒加入到等待佇列中,等待被喚醒,release方法用來釋放鎖。 一般來說實現的時候這兩個方法被封裝為lockunlock方法。

下面的SimpleLock類實現了一個最簡單非重入的互斥鎖的功能,實際上它就是ThreadPoolExecutor$Worker的實現(以後的文章會提到這個類)。

class SimpleLock extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -7316320116933187634L; public SimpleLock() { } protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
} protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
} public void lock() {
acquire(1);
} public boolean tryLock() {
return tryAcquire(1);
} public void unlock() {
release(1);
} public boolean isLocked() {
return isHeldExclusively();
}
}
public static void main(String[] args) throws InterruptedException {
final SimpleLock lock = new SimpleLock();
lock.lock(); for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
System.out.println(Thread.currentThread().getId() + " acquired the lock!");
lock.unlock();
}
}).start();
// 簡單的讓執行緒按照for迴圈的順序阻塞在lock上
Thread.sleep(100);
} System.out.println("main thread unlock!");
lock.unlock();
}

執行上面的測試程式碼,結果如下:

main thread unlock!
9 acquired the lock!
10 acquired the lock!
11 acquired the lock!
12 acquired the lock!
13 acquired the lock!
14 acquired the lock!
15 acquired the lock!
16 acquired the lock!
17 acquired the lock!
18 acquired the lock!

會發現等待的執行緒是按照阻塞時的順序依次獲取到鎖的。 這是因為AQS是基於一個叫CLH lock queue的一個變種來實現執行緒阻塞佇列的,我們下一篇文章就來簡單瞭解下CLH lock queue。

後續文章計劃如下:

  • 《Java併發包原始碼學習之AQS框架(二)CLH lock queue和自旋鎖》
  • 《Java併發包原始碼學習之AQS框架(三)LockSupport》
  • 《Java併發包原始碼學習之AQS框架(四)AbstractQueuedSynchronizer原始碼分析》
  • 《Java併發包原始碼學習之AQS框架(五)ConditionObject原始碼分析》

  ……

  • 《Java併發包原始碼學習之鎖(一)概述》
  • 《Java併發包原始碼學習之鎖(二)ReentrantLock原始碼分析》

  ……

  • 《Java併發包原始碼學習之執行緒池(一)概述》
  • 《Java併發包原始碼學習之執行緒池(二)ThreadPoolExecutor原始碼分析》

  ……

學習Java併發包原始碼的初衷是為了搞清之前遇到的一個問題,其實很早之前就打算看這塊的原始碼但一直沒看下去,所以說 看原始碼一定要有目的不能為了看而看。