標籤:
AQS其實就是java.util.concurrent.locks.AbstractQueuedSynchronizer
這個類。 閱讀Java的並發包源碼你會發現這個類是整個java.util.concurrent
的核心之一,也可以說是閱讀整個並發包源碼的一個突破口。
比如讀ReentrantLock
的源碼你會發現其核心是它的一個內部類Sync
:
整個包中很多類的結構都是如此,比如Semaphore
,CountDownLatch
都有一個內部類Sync
,而所有的Sync都是繼承自AbstractQueuedSynchronizer
。 所以說想要讀懂Java並發包的代碼,首先得讀懂這個類。
AQS簡核心是通過一個共用變數來同步狀態,變數的狀態由子類去維護,而AQS架構做的是:
共用變數的修改都是通過Unsafe
類提供的CAS操作完成的。AbstractQueuedSynchronizer
類的主要方法是acquire
和release
,典型的模板方法, 下面這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方法用來釋放鎖。 一般來說實現的時候這兩個方法被封裝為lock
和unlock
方法。
下面的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並發包源碼的初衷是為了搞清之前遇到的一個問題,其實很早之前就打算看這塊的源碼但一直沒看下去,所以說 看源碼一定要有目的不能為了看而看。
Java並發包源碼學習之AQS架構(一)概述